Contiki-NG
power-mgmt.c
1 /*
2  * Copyright (c) 2016, Zolertia - http://www.zolertia.com
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup remote-power-mgmt-revb
33  * @{
34  * RE-Mote power management functions.
35  *
36  * @{
37  *
38  * \author
39  * Aitor Mejias <amejias@zolertia.com>
40  * Antonio Lignan <alinan@zolertia.com>
41  */
42 /* -------------------------------------------------------------------------- */
43 #include <stdio.h>
44 #include <stdint.h>
45 #include "contiki.h"
46 #include "dev/gpio.h"
47 #include "sys/rtimer.h"
48 #include "power-mgmt.h"
49 #include "dev/i2c.h"
50 /* -------------------------------------------------------------------------- */
51 #define DEBUG 0
52 #if DEBUG
53 #define PRINTF(...) printf(__VA_ARGS__)
54 #else
55 #define PRINTF(...)
56 #endif
57 /* -------------------------------------------------------------------------- */
58 #define PM_ENABLE_LINE_SET GPIO_SET_PIN(PM_ENABLE_PORT_BASE, \
59  PM_ENABLE_PIN_MASK)
60 #define PM_ENABLE_LINE_CLR GPIO_CLR_PIN(PM_ENABLE_PORT_BASE, \
61  PM_ENABLE_PIN_MASK)
62 #define PM_ENABLE_AS_OUTPUT GPIO_SET_OUTPUT(PM_ENABLE_PORT_BASE, \
63  PM_ENABLE_PIN_MASK)
64 #define PM_ENABLE_LINE_CMD PM_ENABLE_LINE_SET; \
65  clock_delay_usec(100);
66 
67 /* -------------------------------------------------------------------------- */
68 #define PM_NUMBITS(X) (1 << ((X)-1))
69 /* -------------------------------------------------------------------------- */
70 static uint8_t initialized = 0;
71 static uint8_t lbuf[5];
72 /* -------------------------------------------------------------------------- */
73 int8_t
74 pm_enable(void)
75 {
76  /* Set as output/low to set IDLE state */
77  GPIO_SOFTWARE_CONTROL(PM_ENABLE_PORT_BASE, PM_ENABLE_PIN_MASK);
78  PM_ENABLE_AS_OUTPUT;
79 
80  i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN,
81  I2C_SCL_NORMAL_BUS_SPEED);
82  initialized = 1;
83  return PM_SUCCESS;
84 }
85 /* -------------------------------------------------------------------------- */
86 static int
87 pm_write_byte(uint8_t reg, uint8_t val)
88 {
89  if(!initialized) {
90  return PM_ERROR;
91  }
92  lbuf[0] = reg;
93  lbuf[1] = val;
94  PM_ENABLE_LINE_CMD;
95 
96  if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) {
97  PM_ENABLE_LINE_CLR;
98  return PM_SUCCESS;
99  }
100  PM_ENABLE_LINE_CLR;
101  return PM_ERROR;
102 }
103 /*---------------------------------------------------------------------------*/
104 static int
105 pm_read_byte(uint8_t reg, uint8_t *val, uint8_t len)
106 {
107  /* Detect valid register parameter */
108  if((reg < PM_VBAT) || (reg >= PM_MAX_COMMANDS) || (!len)) {
109  PRINTF("PM: invalid settings/not initialized\n");
110  return PM_ERROR;
111  }
112 
113  PM_ENABLE_LINE_CMD;
114 
115  if(i2c_single_send(PWR_MNGMT_ADDR, reg) == I2C_MASTER_ERR_NONE) {
116  if(i2c_burst_receive(PWR_MNGMT_ADDR, val, len) == I2C_MASTER_ERR_NONE) {
117  printf("PM: Data 0x%02X\n", *val);
118  PM_ENABLE_LINE_CLR;
119  return PM_SUCCESS;
120  }
121  }
122  PRINTF("PM: Error reading the registers\n");
123  PM_ENABLE_LINE_CLR;
124  return PM_ERROR;
125 }
126 /* -------------------------------------------------------------------------- */
127 int8_t
129 {
130  if(!initialized) {
131  return PM_ERROR;
132  }
133 
134  /* Reset the low-power PIC and the whole board as a bonus */
135  lbuf[0] = PM_CMD_RST_HARD;
136  lbuf[1] = 1;
137  PM_ENABLE_LINE_CMD;
138 
139  if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) {
140  clock_delay_usec(1000);
141  PM_ENABLE_LINE_CLR;
142  return PM_SUCCESS;
143  }
144  PM_ENABLE_LINE_CLR;
145  return PM_ERROR;
146 }
147 /* -------------------------------------------------------------------------- */
148 int8_t
149 pm_set_timeout(uint32_t time)
150 {
151  if(!initialized) {
152  return PM_ERROR;
153  }
154 
155  if(time > PM_SOFT_SHTDN_28_DAYS) {
156  PRINTF("PM: maximum timeout is %u\n", (uint32_t)PM_SOFT_SHTDN_28_DAYS);
157  return PM_ERROR;
158  }
159 
160  lbuf[0] = PM_SOFT_TIME;
161  lbuf[1] = (uint8_t)(time >> 24);
162  lbuf[2] = (uint8_t)(time >> 16) & 0xFF;
163  lbuf[3] = (uint8_t)(time >> 8) & 0xFF;
164  lbuf[4] = (uint8_t)(time & 0xFF);
165  PRINTF("PM: Timeout 0x%02x%02x%02x%02x\n", lbuf[1], lbuf[2], lbuf[3], lbuf[4]);
166 
167  PM_ENABLE_LINE_CMD;
168 
169  if(i2c_burst_send(PWR_MNGMT_ADDR, lbuf, 5) == I2C_MASTER_ERR_NONE) {
170  PM_ENABLE_LINE_CLR;
171  return PM_SUCCESS;
172  }
173 
174  PRINTF("PM: error setting the timeout\n");
175  PM_ENABLE_LINE_CLR;
176  return PM_ERROR;
177 }
178 /* -------------------------------------------------------------------------- */
179 uint32_t
181 {
182  uint32_t retval = 0;
183  PM_ENABLE_LINE_CMD;
184 
185  if(i2c_single_send(PWR_MNGMT_ADDR, PM_SOFT_TIME) == I2C_MASTER_ERR_NONE) {
186  if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 4) == I2C_MASTER_ERR_NONE) {
187  retval |= ((uint32_t)lbuf[0] << 24);
188  retval |= ((uint32_t)lbuf[1] << 16);
189  retval |= ((uint32_t)lbuf[2] << 8);
190  retval |= lbuf[3];
191  }
192  }
193 
194  PM_ENABLE_LINE_CLR;
195  PRINTF("PM: Timeout 0x%02x%02x%02x%02x\n", lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
196 
197  retval *= PM_SOFT_SHTDN_INTERVAL;
198  retval /= 100;
199  return retval;
200 }
201 /* -------------------------------------------------------------------------- */
202 uint32_t
204 {
205  uint32_t retval = 0;
206  PM_ENABLE_LINE_CMD;
207 
208  if(i2c_single_send(PWR_MNGMT_ADDR, PM_GET_NUM_CYCLES) == I2C_MASTER_ERR_NONE) {
209  if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 4) == I2C_MASTER_ERR_NONE) {
210  retval |= ((uint32_t)lbuf[0] << 24);
211  retval |= ((uint32_t)lbuf[1] << 16);
212  retval |= ((uint32_t)lbuf[2] << 8);
213  retval |= lbuf[3];
214  }
215  }
216  PM_ENABLE_LINE_CLR;
217  PRINTF("PM: Sleep cycles: 0x%02x%02x%02x%02x\n", lbuf[0], lbuf[1], lbuf[2],
218  lbuf[3]);
219  return retval;
220 }
221 /* -------------------------------------------------------------------------- */
222 int8_t
223 pm_shutdown_now(uint8_t type)
224 {
225  if(!initialized) {
226  PRINTF("PM: Not initialized\n");
227  return PM_ERROR;
228  }
229 
230  if((type != PM_HARD_SLEEP_CONFIG) && (type != PM_SOFT_SLEEP_CONFIG)) {
231  PRINTF("PM: Invalid shutdown mode type\n");
232  return PM_ERROR;
233  }
234 
235  PM_ENABLE_LINE_CMD;
236 
237  if(type == PM_HARD_SLEEP_CONFIG) {
238  pm_write_byte(PM_HARD_SLEEP_CONFIG, PM_ENABLE);
239  PM_ENABLE_LINE_CLR;
240  return PM_SUCCESS;
241  }
242 
243  /* Soft sleep */
244  pm_write_byte(PM_SOFT_SLEEP_CONFIG, PM_ENABLE);
245  PM_ENABLE_LINE_CLR;
246  return PM_SUCCESS;
247 }
248 /* -------------------------------------------------------------------------- */
249 int8_t
250 pm_get_voltage(uint16_t *state)
251 {
252  float result = 0x00;
253 
254  if(!initialized) {
255  return PM_ERROR;
256  }
257 
258  PM_ENABLE_LINE_CMD;
259  if(i2c_single_send(PWR_MNGMT_ADDR, PM_GET_VDD) == I2C_MASTER_ERR_NONE) {
260  /* Read two bytes only */
261  if(i2c_burst_receive(PWR_MNGMT_ADDR, lbuf, 2) == I2C_MASTER_ERR_NONE) {
262  *state = (uint16_t)lbuf[0] << 8;
263  *state += lbuf[1];
264 
265  /* Compensation */
266  result = *state - PM_VBAT_OFF;
267  result /= PM_VBAT_MULT;
268 
269  *state = (uint16_t)(result * 100);
270 
271  PM_ENABLE_LINE_CLR;
272  return PM_SUCCESS;
273  }
274  }
275  PM_ENABLE_LINE_CLR;
276  return PM_ERROR;
277 }
278 /* -------------------------------------------------------------------------- */
279 int8_t
280 pm_get_fw_ver(uint8_t *fwver)
281 {
282  if((!initialized) || (fwver == NULL)) {
283  return PM_ERROR;
284  }
285 
286  if(pm_read_byte(PM_FW_VERSION, fwver, 1) == PM_SUCCESS) {
287  return PM_SUCCESS;
288  }
289  return PM_ERROR;
290 }
291 /*---------------------------------------------------------------------------*/
292 /**
293  * @}
294  * @}
295  */
uint8_t i2c_burst_send(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to send multiple bytes to a slave.
Definition: i2c.c:188
Header file with register and macro declarations for the cc2538 GPIO module.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
int8_t pm_enable(void)
Initializes the Power Management driver.
Definition: power-mgmt.c:74
int8_t pm_reset_system(void)
Restarts the on-board low-power PIC, provoking a board reset.
Definition: power-mgmt.c:128
#define PWR_MNGMT_ADDR
Power Management slave address.
Definition: power-mgmt.h:61
uint32_t pm_get_num_cycles(void)
Gets current cycles.
Definition: power-mgmt.c:203
int8_t pm_get_fw_ver(uint8_t *fwver)
Gets the current firmware version of power management module.
Definition: power-mgmt.c:280
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
Definition: gpio.h:258
void i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, uint32_t bus_speed)
Initialize the I2C peripheral and pins.
Definition: i2c.c:49
Header file for the real-time timer module.
Header file for the RE-Mote Power Management driver.
int8_t pm_get_voltage(uint16_t *state)
Reads the voltage of the external battery if connected to VIN pin.
Definition: power-mgmt.c:250
uint8_t i2c_burst_receive(uint8_t slave_addr, uint8_t *data, uint8_t len)
Perform all operations to receive multiple bytes from a slave.
Definition: i2c.c:218
int8_t pm_shutdown_now(uint8_t type)
Disconnects the board battery and enter shutdown mode PM_SOFT/HARD_SLEEP_CONFIG.
Definition: power-mgmt.c:223
uint32_t pm_get_timeout(void)
Gets the current timeout value configured in power management module.
Definition: power-mgmt.c:180
uint8_t i2c_single_send(uint8_t slave_addr, uint8_t data)
Perform all operations to send a byte to a slave.
Definition: i2c.c:159
int8_t pm_set_timeout(uint32_t time)
Configure Internal Timeout for Hard and Soft shutdown modes.
Definition: power-mgmt.c:149