| /* cc2520_arch.h - TI CC2520 arch/driver model specific header */ |
| |
| /* |
| * Copyright (c) 2015 Intel Corporation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* You should not include this file directly and it should only be |
| * included by board.h file. |
| */ |
| |
| #ifndef __CC2520_ARCH_H__ |
| #define __CC2520_ARCH_H__ |
| |
| #include <nanokernel.h> |
| #include <stdbool.h> |
| #include <string.h> |
| |
| #include <spi.h> |
| #include <gpio.h> |
| |
| #include "cc2520.h" |
| |
| #if CONFIG_TI_CC2520_DEBUG |
| |
| #define DRIVER_STR "TI cc2520 driver" |
| |
| #if defined(CONFIG_STDOUT_CONSOLE) |
| #include <stdio.h> |
| #define DBG printf |
| #else |
| #include <misc/printk.h> |
| #define DBG printk |
| #endif |
| #else |
| #define DBG(...) |
| #endif /* CONFIG_TI_CC2520_DEBUG */ |
| |
| #ifndef CLOCK_CYCLE_LT |
| #define CLOCK_CYCLE_LT(a, b) ((signed)((a)-(b)) < 0) |
| #endif |
| |
| #ifndef CLOCK_MSEC_TO_CYCLES |
| #define CLOCK_MSEC_TO_CYCLES(msec) \ |
| ((msec) * sys_clock_hw_cycles_per_tick * \ |
| sys_clock_us_per_tick / 1000) |
| #endif |
| |
| #define CONFIG_CC2520_DRV_NAME "CC2520" |
| |
| struct cc2520_gpio_config { |
| struct device *gpio; |
| }; |
| |
| struct cc2520_config { |
| struct cc2520_gpio_config **gpios; |
| struct device *spi; |
| uint32_t spi_slave; |
| }; |
| |
| extern struct cc2520_gpio_config cc2520_gpio_config[CC2520_GPIO_IDX_LAST_ENTRY]; |
| extern struct cc2520_config cc2520_config; |
| extern struct device *cc2520_sgl_dev; |
| |
| typedef void (*cc2520_gpio_int_handler_t)(struct device *port, uint32_t pin); |
| |
| struct cc2520_gpio_config **cc2520_gpio_configure(void); |
| |
| #define CC2520_GPIO(p) \ |
| (((struct device *)& \ |
| ((struct cc2520_config *) \ |
| cc2520_sgl_dev-> \ |
| config->config_info)->gpios[CC2520_GPIO_IDX_ ## p]->gpio)) |
| |
| #define CC2520_SPI() \ |
| (((struct cc2520_config *) \ |
| cc2520_sgl_dev->config->config_info)->spi) |
| |
| #define CC2520_SPI_SLAVE() \ |
| (((struct cc2520_config *) \ |
| cc2520_sgl_dev->config->config_info)->spi_slave) |
| |
| static inline bool spi_transfer(struct device *dev, |
| uint8_t *data_out, uint8_t *data_in, int len) |
| { |
| uint32_t out_len, in_len; |
| int ret; |
| |
| out_len = data_out ? len : 0; |
| in_len = data_in ? len : 0; |
| |
| spi_slave_select(dev, CC2520_SPI_SLAVE()); |
| ret = spi_transceive(dev, data_out, out_len, data_in, in_len); |
| |
| return (ret == DEV_OK); |
| } |
| |
| static inline bool cc2520_read_fifo_buf(uint8_t *buffer, uint32_t count) |
| { |
| uint8_t data[128 + 1] = { 0xff }; |
| bool ret; |
| |
| data[0] = CC2520_INS_RXBUF; |
| |
| ret = spi_transfer(CC2520_SPI(), data, data, count + 1); |
| if (ret) { |
| memcpy(buffer, data + 1, count); |
| } |
| |
| return ret; |
| } |
| |
| static inline bool cc2520_write_fifo_buf(uint8_t *buffer, int count) |
| { |
| uint8_t data[128 + 1]; |
| |
| if (count > (sizeof(data) - 1)) { |
| DBG("%s: too long data %d, max is %d\n", __func__, |
| count, sizeof(data) - 1); |
| return false; |
| } |
| |
| data[0] = CC2520_INS_TXBUF; |
| memcpy(&data[1], buffer, count); |
| |
| return spi_transfer(CC2520_SPI(), data, NULL, count + 1); |
| } |
| |
| static inline bool cc2520_write_reg(uint16_t addr, uint16_t value) |
| { |
| uint8_t data[3]; |
| |
| data[0] = (CC2520_INS_MEMWR | (addr >> 8)) & 0xff; |
| data[1] = addr & 0xff; |
| data[2] = value & 0xff; |
| |
| return spi_transfer(CC2520_SPI(), data, NULL, 3); |
| } |
| |
| static inline bool cc2520_read_reg(uint16_t addr, uint16_t *value) |
| { |
| uint8_t data[3]; |
| bool ret; |
| |
| data[0] = (CC2520_INS_MEMRD | (addr >> 8)) & 0xff; |
| data[1] = addr & 0xff; |
| data[2] = 0; |
| |
| ret = spi_transfer(CC2520_SPI(), data, data, 3); |
| *value = data[2]; |
| |
| return ret; |
| } |
| |
| static inline bool cc2520_write_ram(uint8_t *buffer, int addr, int count) |
| { |
| uint8_t data[128 + 1 + 1]; |
| |
| if (count > (sizeof(data) - 2)) { |
| DBG("%s: too long data %d, max is %d\n", |
| __func__, count, sizeof(data) - 2); |
| return false; |
| } |
| |
| data[0] = (CC2520_INS_MEMWR | (addr >> 8)) & 0xff; |
| data[1] = addr & 0xff; |
| memcpy(&data[2], buffer, count); |
| |
| return spi_transfer(CC2520_SPI(), data, NULL, count + 2); |
| } |
| |
| static inline bool cc2520_read_ram(uint8_t *buffer, int addr, uint32_t count) |
| { |
| uint8_t data[128 + 1 + 1] = { 0 }; |
| int ret; |
| |
| data[0] = (CC2520_INS_MEMRD | (addr >> 8)) & 0xff; |
| data[1] = addr & 0xff; |
| |
| ret = spi_transfer(CC2520_SPI(), data, data, count + 2); |
| memcpy(buffer, data + 2, count); |
| |
| return (!ret); |
| } |
| |
| static inline bool cc2520_get_status(uint8_t *status) |
| { |
| uint8_t data = CC2520_INS_SNOP; |
| |
| return spi_transfer(CC2520_SPI(), &data, status, 1); |
| } |
| |
| static inline bool cc2520_strobe(uint8_t strobe) |
| { |
| return spi_transfer(CC2520_SPI(), &strobe, NULL, 1); |
| } |
| |
| static inline bool cc2520_strobe_plus_nop(uint8_t strobe) |
| { |
| uint8_t data[2]; |
| |
| data[0] = strobe; |
| data[1] = CC2520_INS_SNOP; |
| |
| return spi_transfer(CC2520_SPI(), data, NULL, 2); |
| } |
| |
| static inline int cc2520_get_fifop(void) |
| { |
| uint32_t value; |
| |
| gpio_pin_read(CC2520_GPIO(FIFOP), CONFIG_CC2520_GPIO_FIFOP, &value); |
| |
| return value; |
| } |
| |
| static inline int cc2520_get_fifo(void) |
| { |
| uint32_t value; |
| |
| gpio_pin_read(CC2520_GPIO(FIFO), CONFIG_CC2520_GPIO_FIFO, &value); |
| |
| return value; |
| } |
| |
| static inline int cc2520_get_sfd(void) |
| { |
| uint32_t value; |
| |
| gpio_pin_read(CC2520_GPIO(SFD), CONFIG_CC2520_GPIO_SFD, &value); |
| |
| return value; |
| } |
| |
| static inline int cc2520_get_cca(void) |
| { |
| uint32_t value; |
| |
| gpio_pin_read(CC2520_GPIO(CCA), CONFIG_CC2520_GPIO_CCA, &value); |
| |
| return value; |
| } |
| |
| static inline void cc2520_set_vreg(int enable) |
| { |
| /* If VREG_EN is connected to VDD, then set the gpio pointer |
| * to NULL and do not configure. |
| */ |
| if (!CC2520_GPIO(VREG)) { |
| return; |
| } |
| |
| gpio_pin_write(CC2520_GPIO(VREG), CONFIG_CC2520_GPIO_VREG, enable); |
| } |
| |
| static inline void cc2520_set_reset(int enable) |
| { |
| gpio_pin_write(CC2520_GPIO(RESET), CONFIG_CC2520_GPIO_RESET, enable); |
| } |
| |
| static inline void cc2520_enable_fifop_int(int enable) |
| { |
| DBG("%s FIFOP\n", enable ? "enable" : "disable"); |
| |
| if (enable) { |
| gpio_pin_enable_callback(CC2520_GPIO(FIFOP), |
| CONFIG_CC2520_GPIO_FIFOP); |
| } else { |
| gpio_pin_disable_callback(CC2520_GPIO(FIFOP), |
| CONFIG_CC2520_GPIO_FIFOP); |
| } |
| } |
| |
| static inline void cc2520_clear_fifop_int(void) |
| { |
| /* Do nothing */ |
| } |
| |
| static inline void cc2520_init_fifop_int(cc2520_gpio_int_handler_t handler) |
| { |
| gpio_set_callback(CC2520_GPIO(FIFOP), handler); |
| } |
| |
| #endif /* __CC2520_ARCH_H__ */ |