diff --git a/arch/arm/src/kinetis/Make.defs b/arch/arm/src/kinetis/Make.defs index 29eec9505a..bb7f54d87b 100644 --- a/arch/arm/src/kinetis/Make.defs +++ b/arch/arm/src/kinetis/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # arch/arm/src/kinetis/Make.defs # -# Copyright (C) 2011, 2013-2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2011, 2013-2016 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without diff --git a/arch/arm/src/kinetis/kinetis_alarm.h b/arch/arm/src/kinetis/kinetis_alarm.h index ee135a5eb2..751cfd8cf0 100644 --- a/arch/arm/src/kinetis/kinetis_alarm.h +++ b/arch/arm/src/kinetis/kinetis_alarm.h @@ -1,3 +1,38 @@ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_alarm.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Matias v01d + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + #ifndef __ARCH_ARM_SRC_KINETIS_ALARM_H #define __ARCH_ARM_SRC_KINETIS_ALARM_H diff --git a/arch/arm/src/kinetis/kinetis_i2c.c b/arch/arm/src/kinetis/kinetis_i2c.c index 7ae099a685..1e0987378b 100644 --- a/arch/arm/src/kinetis/kinetis_i2c.c +++ b/arch/arm/src/kinetis/kinetis_i2c.c @@ -1,3 +1,38 @@ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_i2c.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Matias v01d + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + /**************************************************************************** * Included Files ****************************************************************************/ @@ -31,14 +66,13 @@ #include "kinetis.h" #include "kinetis_i2c.h" - #if defined(CONFIG_KINETIS_I2C0) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define I2C_TIMEOUT (20*1000/CONFIG_USEC_PER_TICK) /* 20 mS */ +#define I2C_TIMEOUT (20*1000/CONFIG_USEC_PER_TICK) /* 20 mS */ #define I2C_DEFAULT_FREQUENCY 400000 @@ -47,35 +81,39 @@ #define STATE_TIMEOUT 2 #define STATE_NAK 3 -/* - * TODO: +/* TODO: * - revisar tamanio de todos los registros (getreg/putreg) */ /**************************************************************************** - * Private Data + * Private Types ****************************************************************************/ struct kinetis_i2cdev_s { - struct i2c_master_s dev; /* Generic I2C device */ - unsigned int base; /* Base address of registers */ - uint16_t irqid; /* IRQ for this device */ - uint32_t baseFreq; /* branch frequency */ + struct i2c_master_s dev; /* Generic I2C device */ + unsigned int base; /* Base address of registers */ + uint16_t irqid; /* IRQ for this device */ + uint32_t baseFreq; /* branch frequency */ - sem_t mutex; /* Only one thread can access at a time */ - sem_t wait; /* Place to wait for state machine completion */ - volatile uint8_t state; /* State of state machine */ - WDOG_ID timeout; /* watchdog to timeout when bus hung */ - uint32_t frequency; /* Current I2C frequency */ + sem_t mutex; /* Only one thread can access at a time */ + sem_t wait; /* Place to wait for state machine completion */ + volatile uint8_t state; /* State of state machine */ + WDOG_ID timeout; /* watchdog to timeout when bus hung */ + uint32_t frequency; /* Current I2C frequency */ - struct i2c_msg_s *msgs; /* remaining transfers - first one is in progress */ - unsigned int nmsg; /* number of transfer remaining */ + struct i2c_msg_s *msgs; /* remaining transfers - first one is in + * progress */ + unsigned int nmsg; /* number of transfer remaining */ - uint16_t wrcnt; /* number of bytes sent to tx fifo */ - uint16_t rdcnt; /* number of bytes read from rx fifo */ + uint16_t wrcnt; /* number of bytes sent to tx fifo */ + uint16_t rdcnt; /* number of bytes read from rx fifo */ }; +/**************************************************************************** + * Private Data + ****************************************************************************/ + static struct kinetis_i2cdev_s g_i2c_dev; /**************************************************************************** @@ -87,11 +125,11 @@ static void kinetis_i2c_stop(struct kinetis_i2cdev_s *priv); static int kinetis_i2c_interrupt(int irq, FAR void *context); static void kinetis_i2c_timeout(int argc, uint32_t arg, ...); static void kinetis_i2c_setfrequency(struct kinetis_i2cdev_s *priv, - uint32_t frequency); + uint32_t frequency); static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count); + FAR struct i2c_msg_s *msgs, int count); #ifdef CONFIG_I2C_RESET -static int kinetis_i2c_reset(FAR struct i2c_master_s * dev); +static int kinetis_i2c_reset(FAR struct i2c_master_s *dev); #endif /**************************************************************************** @@ -102,7 +140,7 @@ struct i2c_ops_s kinetis_i2c_ops = { .transfer = kinetis_i2c_transfer #ifdef CONFIG_I2C_RESET - , .reset = kinetis_i2c_reset + ,.reset = kinetis_i2c_reset #endif }; @@ -115,169 +153,270 @@ struct i2c_ops_s kinetis_i2c_ops = ****************************************************************************/ static void kinetis_i2c_setfrequency(struct kinetis_i2cdev_s *priv, - uint32_t frequency) + uint32_t frequency) { - if (frequency == priv->frequency) return; + if (frequency == priv->frequency) + { + return; + } - /* TODO: use apropriate definitions */ + /* TODO: use apropriate definitions */ - #if BOARD_BUS_FREQ == 120000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV1152; // 104 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV288; // 416 kHz - } else { - I2C0_F = I2C_F_DIV128; // 0.94 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 108000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV1024; // 105 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV256; // 422 kHz - } else { - I2C0_F = I2C_F_DIV112; // 0.96 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 96000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV960; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV240; // 400 kHz - } else { - I2C0_F = I2C_F_DIV96; // 1.0 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 90000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV896; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV224; // 402 kHz - } else { - I2C0_F = I2C_F_DIV88; // 1.02 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 80000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV768; // 104 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV192; // 416 kHz - } else { - I2C0_F = I2C_F_DIV80; // 1.0 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 72000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV640; // 112 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV192; // 375 kHz - } else { - I2C0_F = I2C_F_DIV72; // 1.0 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 64000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV640; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV160; // 400 kHz - } else { - I2C0_F = I2C_F_DIV64; // 1.0 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 60000000 - if (frequency < 400000) { - I2C0_F = 0x2C; // 104 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x1C; // 416 kHz - } else { - I2C0_F = 0x12; // 938 kHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 56000000 - if (frequency < 400000) { - I2C0_F = 0x2B; // 109 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x1C; // 389 kHz - } else { - I2C0_F = 0x0E; // 1 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 54000000 - if (frequency < 400000) { - I2C0_F = I2C_F_DIV512; // 105 kHz - } else if (frequency < 1000000) { - I2C0_F = I2C_F_DIV128; // 422 kHz - } else { - I2C0_F = I2C_F_DIV56; // 0.96 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 48000000 - if (frequency < 400000) { - I2C0_F = 0x27; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x1A; // 400 kHz - } else { - I2C0_F = 0x0D; // 1 MHz - } - I2C0_FLT = 4; - #elif BOARD_BUS_FREQ == 40000000 - if (frequency < 400000) { - I2C0_F = 0x29; // 104 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x19; // 416 kHz - } else { - I2C0_F = 0x0B; // 1 MHz - } - I2C0_FLT = 3; - #elif BOARD_BUS_FREQ == 36000000 - if (frequency < 400000) { - putreg8(0x28, KINETIS_I2C0_F); // 113 kHz - } else if (frequency < 1000000) { - putreg8(0x19, KINETIS_I2C0_F); // 375 kHz - } else { - putreg8(0x0A, KINETIS_I2C0_F); // 1 MHz - } - putreg8(3, KINETIS_I2C0_FLT); - #elif BOARD_BUS_FREQ == 24000000 - if (frequency < 400000) { - I2C0_F = 0x1F; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x12; // 375 kHz - } else { - I2C0_F = 0x02; // 1 MHz - } - I2C0_FLT = 2; - #elif BOARD_BUS_FREQ == 16000000 - if (frequency < 400000) { - I2C0_F = 0x20; // 100 kHz - } else if (frequency < 1000000) { - I2C0_F = 0x07; // 400 kHz - } else { - I2C0_F = 0x00; // 800 MHz - } - I2C0_FLT = 1; - #elif BOARD_BUS_FREQ == 8000000 - if (frequency < 400000) { - I2C0_F = 0x14; // 100 kHz - } else { - I2C0_F = 0x00; // 400 kHz - } - I2C0_FLT = 1; - #elif BOARD_BUS_FREQ == 4000000 - if (frequency < 400000) { - I2C0_F = 0x07; // 100 kHz - } else { - I2C0_F = 0x00; // 200 kHz - } - I2C0_FLT = 1; - #elif BOARD_BUS_FREQ == 2000000 - I2C0_F = 0x00; // 100 kHz - I2C0_FLT = 1; - #else - #error "F_BUS must be 120, 108, 96, 9, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 16, 8, 4 or 2 MHz" - #endif +#if BOARD_BUS_FREQ == 120000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV1152, KINETIS_I2C0_F); /* 104 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV288, KINETIS_I2C0_F); /* 416 kHz */ + } + else + { + putreg8(I2C_F_DIV128, KINETIS_I2C0_F); /* 0.94 MHz */ + } - priv->frequency = frequency; + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 108000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV1024, KINETIS_I2C0_F); /* 105 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV256, KINETIS_I2C0_F); /* 422 kHz */ + } + else + { + putreg8(I2C_F_DIV112, KINETIS_I2C0_F); /* 0.96 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 96000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV960, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV240, KINETIS_I2C0_F); /* 400 kHz */ + } + else + { + putreg8(I2C_F_DIV96, KINETIS_I2C0_F); /* 1.0 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 90000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV896, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV224, KINETIS_I2C0_F); /* 402 kHz */ + } + else + { + putreg8(I2C_F_DIV88, KINETIS_I2C0_F); /* 1.02 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 80000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV768, KINETIS_I2C0_F); /* 104 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV192, KINETIS_I2C0_F); /* 416 kHz */ + } + else + { + putreg8(I2C_F_DIV80, KINETIS_I2C0_F); /* 1.0 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 72000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV640, KINETIS_I2C0_F); /* 112 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV192, KINETIS_I2C0_F); /* 375 kHz */ + } + else + { + putreg8(I2C_F_DIV72, KINETIS_I2C0_F); /* 1.0 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 64000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV640, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV160, KINETIS_I2C0_F); /* 400 kHz */ + } + else + { + putreg8(I2C_F_DIV64, KINETIS_I2C0_F); /* 1.0 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 60000000 + if (frequency < 400000) + { + putreg8(0x2C, KINETIS_I2C0_F); /* 104 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x1C, KINETIS_I2C0_F); /* 416 kHz */ + } + else + { + putreg8(0x12, KINETIS_I2C0_F); /* 938 kHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 56000000 + if (frequency < 400000) + { + putreg8(0x2B, KINETIS_I2C0_F); /* 109 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x1C, KINETIS_I2C0_F); /* 389 kHz */ + } + else + { + putreg8(0x0E, KINETIS_I2C0_F); /* 1 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 54000000 + if (frequency < 400000) + { + putreg8(I2C_F_DIV512, KINETIS_I2C0_F); /* 105 kHz */ + } + else if (frequency < 1000000) + { + putreg8(I2C_F_DIV128, KINETIS_I2C0_F); /* 422 kHz */ + } + else + { + putreg8(I2C_F_DIV56, KINETIS_I2C0_F); /* 0.96 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 48000000 + if (frequency < 400000) + { + putreg8(0x27, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x1A, KINETIS_I2C0_F); /* 400 kHz */ + } + else + { + putreg8(0x0D, KINETIS_I2C0_F); /* 1 MHz */ + } + + putreg8(4, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 40000000 + if (frequency < 400000) + { + putreg8(0x29, KINETIS_I2C0_F); /* 104 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x19, KINETIS_I2C0_F); /* 416 kHz */ + } + else + { + putreg8(0x0B, KINETIS_I2C0_F); /* 1 MHz */ + } + + putreg8(3, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 36000000 + if (frequency < 400000) + { + putreg8(0x28, KINETIS_I2C0_F); /* 113 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x19, KINETIS_I2C0_F); /* 375 kHz */ + } + else + { + putreg8(0x0A, KINETIS_I2C0_F); /* 1 MHz */ + } + + putreg8(3, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 24000000 + if (frequency < 400000) + { + putreg8(0x1F, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x12, KINETIS_I2C0_F); /* 375 kHz */ + } + else + { + putreg8(0x02, KINETIS_I2C0_F); /* 1 MHz */ + } + + putreg8(2, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 16000000 + if (frequency < 400000) + { + putreg8(0x20, KINETIS_I2C0_F); /* 100 kHz */ + } + else if (frequency < 1000000) + { + putreg8(0x07, KINETIS_I2C0_F); /* 400 kHz */ + } + else + { + putreg8(0x00, KINETIS_I2C0_F); /* 800 MHz */ + } + + putreg8(1, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 8000000 + if (frequency < 400000) + { + putreg8(0x14, KINETIS_I2C0_F); /* 100 kHz */ + } + else + { + putreg8(0x00, KINETIS_I2C0_F); /* 400 kHz */ + } + + putreg8(1, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 4000000 + if (frequency < 400000) + { + putreg8(0x07, KINETIS_I2C0_F); /* 100 kHz */ + } + else + { + putreg8(0x00, KINETIS_I2C0_F); /* 200 kHz */ + } + + putreg8(1, KINETIS_I2C0_FLT); +#elif BOARD_BUS_FREQ == 2000000 + putreg8(0x00, KINETIS_I2C0_F); /* 100 kHz */ + putreg8(1, KINETIS_I2C0_FLT); +#else +# error "F_BUS must be 120, 108, 96, 9, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 16, 8, 4 or 2 MHz" +#endif + + priv->frequency = frequency; } /**************************************************************************** @@ -290,39 +429,50 @@ static void kinetis_i2c_setfrequency(struct kinetis_i2cdev_s *priv, static int kinetis_i2c_start(struct kinetis_i2cdev_s *priv) { - struct i2c_msg_s *msg; + struct i2c_msg_s *msg; msg = priv->msgs; - /* now take control of the bus */ + /* Now take control of the bus */ + if (getreg8(KINETIS_I2C0_C1) & I2C_C1_MST) - { - /* we are already the bus master, so send a repeated start */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX, KINETIS_I2C0_C1); - } - else - { - /* we are not currently the bus master, so wait for bus ready */ - while (getreg8(KINETIS_I2C0_S) & I2C_S_BUSY); + { + /* We are already the bus master, so send a repeated start */ - /* become the bus master in transmit mode (send start) */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); - } - - if (I2C_M_READ & msg->flags) /* DEBUG: should happen always */ - { - /* wait until start condition establishes control of the bus */ - while (1) { - if (getreg8(KINETIS_I2C0_S) & I2C_S_BUSY) break; + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_RSTA | + I2C_C1_TX, KINETIS_I2C0_C1); } - } + else + { + /* We are not currently the bus master, so wait for bus ready */ + + while (getreg8(KINETIS_I2C0_S) & I2C_S_BUSY); + + /* Become the bus master in transmit mode (send start) */ + + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, + KINETIS_I2C0_C1); + } + + if (I2C_M_READ & msg->flags) /* DEBUG: should happen always */ + { + /* Wait until start condition establishes control of the bus */ + + while (1) + { + if (getreg8(KINETIS_I2C0_S) & I2C_S_BUSY) + { + break; + } + } + } + + /* Initiate actual transfer (send address) */ - /* initiate actual transfer (send address) */ putreg8((I2C_M_READ & msg->flags) == I2C_M_READ ? - I2C_READADDR8(msg->addr) : - I2C_WRITEADDR8(msg->addr), KINETIS_I2C0_D); + I2C_READADDR8(msg->addr) : I2C_WRITEADDR8(msg->addr), KINETIS_I2C0_D); - return OK; + return OK; } /**************************************************************************** @@ -393,105 +543,138 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context) struct kinetis_i2cdev_s *priv; struct i2c_msg_s *msg; uint32_t state; - int regval, dummy; + int regval; + int dummy; UNUSED(dummy); if (irq == KINETIS_IRQ_I2C0) - { - priv = &g_i2c_dev; - } + { + priv = &g_i2c_dev; + } else - { - PANIC(); - } + { + PANIC(); + } + + /* Get current state */ - /* get current state */ state = getreg8(KINETIS_I2C0_S); msg = priv->msgs; - /* arbitration lost */ + /* Arbitration lost */ + if (state & I2C_S_ARBL) - { - putreg8(I2C_S_IICIF | I2C_S_ARBL, KINETIS_I2C0_S); - priv->state = STATE_ARBITRATION_ERROR; - kinetis_i2c_stop(priv); - } + { + putreg8(I2C_S_IICIF | I2C_S_ARBL, KINETIS_I2C0_S); + priv->state = STATE_ARBITRATION_ERROR; + kinetis_i2c_stop(priv); + } else - { - /* clear interrupt */ - putreg8(I2C_S_IICIF, KINETIS_I2C0_S); - - regval = getreg8(KINETIS_I2C0_C1); - - /* TX mode */ - if (regval & I2C_C1_TX) { - /* last write was not acknowledged */ - if (state & I2C_S_RXAK) - { - priv->state = STATE_NAK; /* set error flag */ - kinetis_i2c_stop(priv); /* send STOP */ - } - else - { - /* actually intending to write */ - if ((I2C_M_READ & msg->flags) == 0) + /* Clear interrupt */ + + putreg8(I2C_S_IICIF, KINETIS_I2C0_S); + + regval = getreg8(KINETIS_I2C0_C1); + + /* TX mode */ + + if (regval & I2C_C1_TX) { - /* wrote everything */ - if (priv->wrcnt == msg->length) - { - kinetis_i2c_nextmsg(priv); /* continue with next message */ - } + /* Last write was not acknowledged */ + + if (state & I2C_S_RXAK) + { + priv->state = STATE_NAK; /* Set error flag */ + kinetis_i2c_stop(priv); /* Send STOP */ + } else - { - putreg8(msg->buffer[priv->wrcnt], KINETIS_I2C0_D); /* Put next byte */ - priv->wrcnt++; - } + { + /* Actually intending to write */ + + if ((I2C_M_READ & msg->flags) == 0) + { + /* Wrote everything */ + + if (priv->wrcnt == msg->length) + { + /* Continue with next message */ + + kinetis_i2c_nextmsg(priv); + } + else + { + /* Put next byte */ + + putreg8(msg->buffer[priv->wrcnt], KINETIS_I2C0_D); + priv->wrcnt++; + } + } + + /* Actually intending to read (address was just sent) */ + + else + { + if (msg->length == 1) /* go to RX mode, do not send ACK */ + { + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | + I2C_C1_TXAK, KINETIS_I2C0_C1); + } + else /* go to RX mode */ + { + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST, + KINETIS_I2C0_C1); + } + + /* TODO: handle zero-length reads */ + /* Dummy read to initiate reception */ + + dummy = getreg8(KINETIS_I2C0_D); + } + } } - /* actually intending to read (address was just sent) */ - else - { - if (msg->length == 1) /* go to RX mode, do not send ACK */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK, KINETIS_I2C0_C1); - else /* go to RX mode */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST, KINETIS_I2C0_C1); - /* TODO: handle zero-length reads */ + /* RX: mode */ - dummy = getreg8(KINETIS_I2C0_D); /* dummy read to initiate reception */ - } - } - } - /* RX: mode */ - else - { - /* if last receiving byte */ - if (priv->rdcnt == (msg->length - 1)) - { - /* go to TX mode before last read, otherwise a new read is triggered */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); /* go to TX mode */ - - msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); - priv->rdcnt++; - - kinetis_i2c_nextmsg(priv); - } - /* second to last receiving byte */ - else if (priv->rdcnt == (msg->length - 2)) - { - /* Do not ACK any more */ - putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK, KINETIS_I2C0_C1); - - msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); - priv->rdcnt++; - } else - { - msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); - priv->rdcnt++; - } + { + /* If last receiving byte */ + + if (priv->rdcnt == (msg->length - 1)) + { + /* go to TX mode before last read, otherwise a new read is + * triggered. + */ + + /* Go to TX mode */ + + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX, KINETIS_I2C0_C1); + + msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); + priv->rdcnt++; + + kinetis_i2c_nextmsg(priv); + } + + /* Second to last receiving byte */ + + else if (priv->rdcnt == (msg->length - 2)) + { + /* Do not ACK any more */ + + putreg8(I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK, + KINETIS_I2C0_C1); + + msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); + priv->rdcnt++; + } + else + { + msg->buffer[priv->rdcnt] = getreg8(KINETIS_I2C0_D); + priv->rdcnt++; + } + } } - } return OK; } @@ -505,7 +688,7 @@ static int kinetis_i2c_interrupt(int irq, FAR void *context) ****************************************************************************/ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev, - FAR struct i2c_msg_s *msgs, int count) + FAR struct i2c_msg_s *msgs, int count) { struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *)dev; @@ -516,47 +699,58 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev, sem_wait(&priv->mutex); /* Set up for the transfer */ - priv->msgs = msgs; - priv->nmsg = count; + + priv->msgs = msgs; + priv->nmsg = count; priv->state = STATE_OK; - /* Configure the I2C frequency. - * REVISIT: Note that the frequency is set only on the first message. - * This could be extended to support different transfer frequencies for - * each message segment. + /* Configure the I2C frequency. REVISIT: Note that the frequency is set only + * on the first message. This could be extended to support different transfer + * frequencies for each message segment. */ kinetis_i2c_setfrequency(priv, msgs->frequency); - /* clear the status flags */ + /* Clear the status flags */ + putreg8(I2C_S_IICIF | I2C_S_ARBL, KINETIS_I2C0_S); /* Process every message */ + while (priv->nmsg && priv->state == STATE_OK) - { - priv->wrcnt = 0; - priv->rdcnt = 0; + { + priv->wrcnt = 0; + priv->rdcnt = 0; - /* Initiate the transfer */ - kinetis_i2c_start(priv); + /* Initiate the transfer */ - /* wait for transfer complete */ - wd_start(priv->timeout, I2C_TIMEOUT, kinetis_i2c_timeout, 1, (uint32_t)priv); - sem_wait(&priv->wait); + kinetis_i2c_start(priv); - wd_cancel(priv->timeout); - } + /* Wait for transfer complete */ + + wd_start(priv->timeout, I2C_TIMEOUT, kinetis_i2c_timeout, 1, + (uint32_t) priv); + sem_wait(&priv->wait); + + wd_cancel(priv->timeout); + } + + /* Disable interrupts */ - /* disable interrupts */ putreg8(I2C_C1_IICEN, KINETIS_I2C0_C1); - /* release access to I2C bus */ + /* Release access to I2C bus */ + sem_post(&priv->mutex); if (priv->state != STATE_OK) - return -1; + { + return -EIO; + } else - return 0; /* TODO: correct? */ + { + return 0; + } } /************************************************************************************ @@ -574,11 +768,11 @@ static int kinetis_i2c_transfer(FAR struct i2c_master_s *dev, ************************************************************************************/ #ifdef CONFIG_I2C_RESET -static int kinetis_i2c_reset(FAR struct i2c_master_s * dev) +static int kinetis_i2c_reset(FAR struct i2c_master_s *dev) { return OK; } -#endif /* CONFIG_I2C_RESET */ +#endif /* CONFIG_I2C_RESET */ /**************************************************************************** * Public Functions @@ -597,10 +791,10 @@ struct i2c_master_s *kinetis_i2cbus_initialize(int port) struct kinetis_i2cdev_s *priv; if (port > 1) - { - i2cerr("ERROR: Kinetis I2C Only suppors ports 0 and 1\n"); - return NULL; - } + { + i2cerr("ERROR: Kinetis I2C Only suppors ports 0 and 1\n"); + return NULL; + } irqstate_t flags; uint32_t regval; @@ -608,38 +802,43 @@ struct i2c_master_s *kinetis_i2cbus_initialize(int port) flags = enter_critical_section(); if (port == 0) - { - priv = &g_i2c_dev; - priv->base = KINETIS_I2C0_BASE; - priv->irqid = KINETIS_IRQ_I2C0; - priv->baseFreq = BOARD_BUS_FREQ; + { + priv = &g_i2c_dev; + priv->base = KINETIS_I2C0_BASE; + priv->irqid = KINETIS_IRQ_I2C0; + priv->baseFreq = BOARD_BUS_FREQ; - /* Enable clock */ - regval = getreg32(KINETIS_SIM_SCGC4); - regval |= SIM_SCGC4_I2C0; - putreg32(regval, KINETIS_SIM_SCGC4); + /* Enable clock */ - kinetis_i2c_setfrequency(priv, I2C_DEFAULT_FREQUENCY); + regval = getreg32(KINETIS_SIM_SCGC4); + regval |= SIM_SCGC4_I2C0; + putreg32(regval, KINETIS_SIM_SCGC4); - /* Disable while configuring */ - putreg8(0, KINETIS_I2C0_C1); + kinetis_i2c_setfrequency(priv, I2C_DEFAULT_FREQUENCY); - /* Configure pins */ - kinetis_pinconfig(PIN_I2C0_SCL); - kinetis_pinconfig(PIN_I2C0_SDA); + /* Disable while configuring */ - /* Enable */ - putreg8(I2C_C1_IICEN, KINETIS_I2C0_C1); + putreg8(0, KINETIS_I2C0_C1); - /* High-drive select (TODO: why)? */ - regval = getreg8(KINETIS_I2C0_C2); - regval |= I2C_C2_HDRS; - putreg8(regval, KINETIS_I2C0_C2); - } + /* Configure pins */ + + kinetis_pinconfig(PIN_I2C0_SCL); + kinetis_pinconfig(PIN_I2C0_SDA); + + /* Enable */ + + putreg8(I2C_C1_IICEN, KINETIS_I2C0_C1); + + /* High-drive select (TODO: why)? */ + + regval = getreg8(KINETIS_I2C0_C2); + regval |= I2C_C2_HDRS; + putreg8(regval, KINETIS_I2C0_C2); + } else - { - return NULL; - } + { + return NULL; + } leave_critical_section(flags); @@ -673,12 +872,12 @@ struct i2c_master_s *kinetis_i2cbus_initialize(int port) * ****************************************************************************/ -int kinetis_i2cbus_uninitialize(FAR struct i2c_master_s * dev) +int kinetis_i2cbus_uninitialize(FAR struct i2c_master_s *dev) { - struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *) dev; + struct kinetis_i2cdev_s *priv = (struct kinetis_i2cdev_s *)dev; putreg8(0, KINETIS_I2C0_C1); - + up_disable_irq(priv->irqid); irq_detach(priv->irqid); return OK; diff --git a/arch/arm/src/kinetis/kinetis_i2c.h b/arch/arm/src/kinetis/kinetis_i2c.h index b42e248882..098e4d39ad 100644 --- a/arch/arm/src/kinetis/kinetis_i2c.h +++ b/arch/arm/src/kinetis/kinetis_i2c.h @@ -1,3 +1,38 @@ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_i2c.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Matias v01d + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + #ifndef __ARCH_ARM_SRC_KINETIS_KINETIS_I2C_H #define __ARCH_ARM_SRC_KINETIS_KINETIS_I2C_H diff --git a/arch/arm/src/kinetis/kinetis_rtc.c b/arch/arm/src/kinetis/kinetis_rtc.c index 3d0af29c60..ca0f4848d1 100644 --- a/arch/arm/src/kinetis/kinetis_rtc.c +++ b/arch/arm/src/kinetis/kinetis_rtc.c @@ -1,6 +1,41 @@ -/************************************************************************************ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_rtc.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Matias v01d + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include #include @@ -25,269 +60,25 @@ #if defined(CONFIG_RTC) -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/************************************************************************************ +/**************************************************************************** * Private Data - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_RTC_ALARM static alarmcb_t g_alarmcb; #endif -/************************************************************************************ - * Private Declarations - ************************************************************************************/ - -static int kinetis_rtc_interrupt(int irq, void *context); - -/************************************************************************************ +/**************************************************************************** * Public Data - ************************************************************************************/ + ****************************************************************************/ volatile bool g_rtc_enabled = false; -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: up_rtc_initialize - * - * Description: - * Initialize the hardware RTC per the selected configuration. This function is - * called once during the OS initialization sequence - * - * Input Parameters: - * None - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -int up_rtc_initialize(void) -{ - int regval; - - /* enable RTC module */ - regval = getreg32(KINETIS_SIM_SCGC6); - regval |= SIM_SCGC6_RTC; - putreg32(regval, KINETIS_SIM_SCGC6); - - /* disable counters (just in case) */ - putreg32(0, KINETIS_RTC_SR); - - /* enable oscilator */ - putreg32(RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE, KINETIS_RTC_CR); /* capacitance values from teensyduino */ - /* TODO: delay some time (1024 cycles? would be 30ms) */ - - /* disable interrupts */ - putreg32(0, KINETIS_RTC_IER); - - /* reset flags requires writing the seconds register, the following line avoids altering any stored time value */ - putreg32(getreg32(KINETIS_RTC_TSR), KINETIS_RTC_TSR); - -#if defined(CONFIG_RTC_ALARM) - /* enable alarm interrupts */ - irq_attach(KINETIS_IRQ_RTC, kinetis_rtc_interrupt); - up_enable_irq(KINETIS_IRQ_RTC); -#endif - - /* enable counters */ - putreg32(RTC_SR_TCE, KINETIS_RTC_SR); - - /* mark RTC enabled */ - g_rtc_enabled = true; - - return OK; -} - -/************************************************************************************ - * Name: up_rtc_time - * - * Description: - * Get the current time in seconds. This is similar to the standard time() - * function. This interface is only required if the low-resolution RTC/counter - * hardware implementation selected. It is only used by the RTOS during - * initialization to set up the system time when CONFIG_RTC is set but neither - * CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set. - * - * Input Parameters: - * None - * - * Returned Value: - * The current time in seconds - * - ************************************************************************************/ - -#ifndef CONFIG_RTC_HIRES -time_t up_rtc_time(void) -{ - return getreg32(KINETIS_RTC_TSR); -} -#endif - -/************************************************************************************ - * Name: up_rtc_gettime - * - * Description: - * Get the current time from the high resolution RTC clock/counter. This interface - * is only supported by the high-resolution RTC/counter hardware implementation. - * It is used to replace the system timer. - * - * Input Parameters: - * tp - The location to return the high resolution time value. - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -#ifdef CONFIG_RTC_HIRES -int up_rtc_gettime(FAR struct timespec *tp) -{ - irqstate_t flags; - uint32_t seconds, prescaler, prescaler2; - - /* - * get prescaler and seconds register. this is in a loop which - * ensures that registers will be re-read if during the reads the - * prescaler has wrapped-around - */ - - flags = enter_critical_section(); - do - { - prescaler = getreg32(KINETIS_RTC_TPR); - seconds = getreg32(KINETIS_RTC_TSR); - prescaler2 = getreg32(KINETIS_RTC_TPR); - } - while (prescaler > prescaler2); - leave_critical_section(flags); - - /* build seconds + nanoseconds from seconds and prescaler register */ - tp->tv_sec = seconds; - tp->tv_nsec = prescaler * (1000000000 / CONFIG_RTC_FREQUENCY); - return OK; -} -#endif - -/************************************************************************************ - * Name: up_rtc_settime - * - * Description: - * Set the RTC to the provided time. All RTC implementations must be able to - * set their time based on a standard timespec. - * - * Input Parameters: - * tp - the time to use - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -int up_rtc_settime(FAR const struct timespec *tp) -{ - irqstate_t flags; - uint32_t seconds, prescaler; - - seconds = tp->tv_sec; - prescaler = tp->tv_nsec * (CONFIG_RTC_FREQUENCY / 1000000000); - - flags = enter_critical_section(); - - putreg32(0, KINETIS_RTC_SR); /* disable counter */ - - putreg32(prescaler, KINETIS_RTC_TPR); /* always write prescaler first */ - putreg32(seconds, KINETIS_RTC_TSR); - - putreg32(RTC_SR_TCE, KINETIS_RTC_SR); /* re-enable counter */ - - leave_critical_section(flags); - - return OK; -} - -/************************************************************************************ +/**************************************************************************** * Private Functions - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ - * Name: kinetis_rtc_setalarm - * - * Description: - * Set up an alarm. - * - * Input Parameters: - * tp - the time to set the alarm - * callback - the function to call when the alarm expires. - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -#ifdef CONFIG_RTC_ALARM -int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) -{ - /* Is there already something waiting on the ALARM? */ - if (g_alarmcb == NULL) - { - /* No.. Save the callback function pointer */ - - g_alarmcb = callback; - - /* Enable and set RTC alarm */ - - putreg32(tp->tv_sec, KINETIS_RTC_TAR); /* set alarm (also resets flags) */ - putreg32(RTC_IER_TAIE, KINETIS_RTC_IER); /* enable alarm interrupt */ - - return OK; - } - else - return -EBUSY; -} -#endif - -/************************************************************************************ - * Name: kinetis_rtc_cancelalarm - * - * Description: - * Cancel a pending alarm alarm - * - * Input Parameters: - * none - * - * Returned Value: - * Zero (OK) on success; a negated errno on failure - * - ************************************************************************************/ - -#ifdef CONFIG_RTC_ALARM -int kinetis_rtc_cancelalarm(void) -{ - if (g_alarmcb != NULL) - { - /* Cancel the global callback function */ - - g_alarmcb = NULL; - - /* Unset the alarm */ - - putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ - - return OK; - } - else - return -ENODATA; -} -#endif - -/************************************************************************************ +/**************************************************************************** * Name: kinetis_rtc_interrupt * * Description: @@ -300,19 +91,21 @@ int kinetis_rtc_cancelalarm(void) * Returned Value: * Zero (OK) on success; A negated errno value on failure. * - ************************************************************************************/ + ****************************************************************************/ #if defined(CONFIG_RTC_ALARM) static int kinetis_rtc_interrupt(int irq, void *context) { if (g_alarmcb != NULL) - { - /* Alarm callback */ - g_alarmcb(); - g_alarmcb = NULL; - } + { + /* Alarm callback */ + + g_alarmcb(); + g_alarmcb = NULL; + } /* Clear pending flags, disable alarm */ + putreg32(0, KINETIS_RTC_TAR); /* unset alarm (resets flags) */ putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ @@ -320,4 +113,261 @@ static int kinetis_rtc_interrupt(int irq, void *context) } #endif -#endif // KINETIS_RTC +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This + * function is called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_initialize(void) +{ + int regval; + + /* Enable RTC module */ + + regval = getreg32(KINETIS_SIM_SCGC6); + regval |= SIM_SCGC6_RTC; + putreg32(regval, KINETIS_SIM_SCGC6); + + /* Disable counters (just in case) */ + + putreg32(0, KINETIS_RTC_SR); + + /* Enable oscilator */ + /* capacitance values from teensyduino */ + + putreg32(RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE, KINETIS_RTC_CR); + + /* TODO: delay some time (1024 cycles? would be 30ms) */ + + /* Disable interrupts */ + + putreg32(0, KINETIS_RTC_IER); + + /* Reset flags requires writing the seconds register, the following line + * avoids altering any stored time value. + */ + + putreg32(getreg32(KINETIS_RTC_TSR), KINETIS_RTC_TSR); + +#if defined(CONFIG_RTC_ALARM) + /* Enable alarm interrupts. REVISIT: This will not work. up_rtc_initialize() + * is called very early in initialization BEFORE the interrupt system will be + * enabled. All interrupts will disabled later when the interrupt system is + * disabled. This must be done later when the alarm is first set. + */ + + irq_attach(KINETIS_IRQ_RTC, kinetis_rtc_interrupt); + up_enable_irq(KINETIS_IRQ_RTC); +#endif + + /* Enable counters */ + + putreg32(RTC_SR_TCE, KINETIS_RTC_SR); + + /* Mark RTC enabled */ + + g_rtc_enabled = true; + + return OK; +} + +/**************************************************************************** + * Name: up_rtc_time + * + * Description: + * Get the current time in seconds. This is similar to the standard + * time() function. This interface is only required if the low-resolution + * RTC/counter hardware implementation selected. It is only used by the + * RTOS during initialization to set up the system time when CONFIG_RTC is + * set but neither CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set. + * + * Input Parameters: + * None + * + * Returned Value: + * The current time in seconds + * + ****************************************************************************/ + +#ifndef CONFIG_RTC_HIRES +time_t up_rtc_time(void) +{ + return getreg32(KINETIS_RTC_TSR); +} +#endif + +/**************************************************************************** + * Name: up_rtc_gettime + * + * Description: + * Get the current time from the high resolution RTC clock/counter. This + * interface is only supported by the high-resolution RTC/counter hardware + * implementation. It is used to replace the system timer. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_HIRES +int up_rtc_gettime(FAR struct timespec *tp) +{ + irqstate_t flags; + uint32_t seconds, prescaler, prescaler2; + + /* Get prescaler and seconds register. this is in a loop which ensures that + * registers will be re-read if during the reads the prescaler has + * wrapped-around. + */ + + flags = enter_critical_section(); + do + { + prescaler = getreg32(KINETIS_RTC_TPR); + seconds = getreg32(KINETIS_RTC_TSR); + prescaler2 = getreg32(KINETIS_RTC_TPR); + } + while (prescaler > prescaler2); + + leave_critical_section(flags); + + /* Build seconds + nanoseconds from seconds and prescaler register */ + + tp->tv_sec = seconds; + tp->tv_nsec = prescaler * (1000000000 / CONFIG_RTC_FREQUENCY); + return OK; +} +#endif + +/**************************************************************************** + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able + * to set their time based on a standard timespec. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_settime(FAR const struct timespec *tp) +{ + irqstate_t flags; + uint32_t seconds, prescaler; + + seconds = tp->tv_sec; + prescaler = tp->tv_nsec * (CONFIG_RTC_FREQUENCY / 1000000000); + + flags = enter_critical_section(); + + putreg32(0, KINETIS_RTC_SR); /* Disable counter */ + + putreg32(prescaler, KINETIS_RTC_TPR); /* Always write prescaler first */ + putreg32(seconds, KINETIS_RTC_TSR); + + putreg32(RTC_SR_TCE, KINETIS_RTC_SR); /* Re-enable counter */ + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: kinetis_rtc_setalarm + * + * Description: + * Set up an alarm. + * + * Input Parameters: + * tp - the time to set the alarm + * callback - the function to call when the alarm expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) +{ + /* Is there already something waiting on the ALARM? */ + + if (g_alarmcb == NULL) + { + /* No.. Save the callback function pointer */ + + g_alarmcb = callback; + + /* Enable and set RTC alarm */ + + putreg32(tp->tv_sec, KINETIS_RTC_TAR); /* Set alarm (also resets + * flags) */ + putreg32(RTC_IER_TAIE, KINETIS_RTC_IER); /* Enable alarm interrupt */ + + return OK; + } + else + { + return -EBUSY; + } +} +#endif + +/**************************************************************************** + * Name: kinetis_rtc_cancelalarm + * + * Description: + * Cancel a pending alarm alarm + * + * Input Parameters: + * none + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int kinetis_rtc_cancelalarm(void) +{ + if (g_alarmcb != NULL) + { + /* Cancel the global callback function */ + + g_alarmcb = NULL; + + /* Unset the alarm */ + + putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ + + return OK; + } + else + { + return -ENODATA; + } +} +#endif + +#endif /* KINETIS_RTC */ diff --git a/configs/teensy-3.x/include/board.h b/configs/teensy-3.x/include/board.h index b95734a04a..38a84af657 100644 --- a/configs/teensy-3.x/include/board.h +++ b/configs/teensy-3.x/include/board.h @@ -243,7 +243,7 @@ #endif #ifdef CONFIG_KINETIS_I2C1 -#error I2C1 not currently supported +# error I2C1 not currently supported #endif /************************************************************************************ diff --git a/configs/teensy-3.x/src/k20_boot.c b/configs/teensy-3.x/src/k20_boot.c index cfb62f9b26..e6447871e6 100644 --- a/configs/teensy-3.x/src/k20_boot.c +++ b/configs/teensy-3.x/src/k20_boot.c @@ -1,7 +1,7 @@ /************************************************************************************ * configs/teensy-3.x/src/k20_boot.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,14 +47,6 @@ #include "up_arch.h" #include "teensy-3x.h" -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/************************************************************************************ - * Private Functions - ************************************************************************************/ - /************************************************************************************ * Public Functions ************************************************************************************/ @@ -93,8 +85,7 @@ void kinetis_boardinitialize(void) void board_initialize(void) { #if defined(CONFIG_KINETIS_I2C0) || defined(CONFIG_KINETIS_I2C1) - //if (kinetis_i2cdev_initialize) - kinetis_i2cdev_initialize(); + kinetis_i2cdev_initialize(); #endif } #endif diff --git a/configs/teensy-3.x/src/k20_i2c.c b/configs/teensy-3.x/src/k20_i2c.c index b6393b11d1..f1440882fd 100644 --- a/configs/teensy-3.x/src/k20_i2c.c +++ b/configs/teensy-3.x/src/k20_i2c.c @@ -1,3 +1,38 @@ +/**************************************************************************** + * configs/teensy-3.x/src/k20_i2c.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Matias v01d + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + /************************************************************************************ * Included Files ************************************************************************************/