1297 lines
35 KiB
C
1297 lines
35 KiB
C
/****************************************************************************
|
|
* arch/arm/src/stm32/stm32_1wire.c
|
|
*
|
|
* Copyright (C) 2016 Aleksandr Vyhovanec. All rights reserved.
|
|
* Author: Aleksandr Vyhovanec <www.desh@gmail.com>
|
|
*
|
|
* 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* Links:
|
|
* https://www.maximintegrated.com/en/app-notes/index.mvp/id/214
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <semaphore.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/clock.h>
|
|
#include <nuttx/semaphore.h>
|
|
#include <nuttx/drivers/1wire.h>
|
|
|
|
#include <arch/board/board.h>
|
|
|
|
#include "up_arch.h"
|
|
|
|
#include "stm32_rcc.h"
|
|
#include "stm32_1wire.h"
|
|
|
|
#ifdef HAVE_1WIREDRIVER
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define BUS_TIMEOUT 5 /* tv_sec */
|
|
|
|
#define RESET_BAUD 9600
|
|
#define RESET_TX 0xF0
|
|
#define TIMESLOT_BAUD 115200
|
|
#define READ_TX 0xFF
|
|
#define READ_RX1 0xFF
|
|
#define WRITE_TX0 0x00
|
|
#define WRITE_TX1 0xFF
|
|
|
|
#define PIN_OPENDRAIN(GPIO) ((GPIO) | GPIO_CNF_OUTOD)
|
|
|
|
#if defined(CONFIG_STM32_STM32F10XX)
|
|
# define USART_CR3_ONEBIT (0)
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/* 1-Wire bus task */
|
|
|
|
enum stm32_1wire_msg_e
|
|
{
|
|
ONEWIRETASK_NONE = 0,
|
|
ONEWIRETASK_RESET,
|
|
ONEWIRETASK_WRITE,
|
|
ONEWIRETASK_READ
|
|
};
|
|
|
|
struct stm32_1wire_msg_s
|
|
{
|
|
enum stm32_1wire_msg_e task; /* Task */
|
|
uint8_t *buffer; /* Task buffer */
|
|
int buflen; /* Buffer length */
|
|
};
|
|
|
|
/* 1-Wire device hardware configuration */
|
|
|
|
struct stm32_1wire_config_s
|
|
{
|
|
const uint32_t usartbase; /* Base address of USART registers */
|
|
const uint32_t apbclock; /* PCLK 1 or 2 frequency */
|
|
const uint32_t data_pin; /* GPIO configuration for DATA */
|
|
const uint8_t irq; /* IRQ associated with this USART */
|
|
};
|
|
|
|
/* 1-Wire device Private Data */
|
|
|
|
struct stm32_1wire_priv_s
|
|
{
|
|
const struct stm32_1wire_config_s *config; /* Port configuration */
|
|
volatile int refs; /* Referernce count */
|
|
sem_t sem_excl; /* Mutual exclusion semaphore */
|
|
sem_t sem_isr; /* Interrupt wait semaphore */
|
|
int baud; /* Baud rate */
|
|
const struct stm32_1wire_msg_s *msgs; /* Messages data */
|
|
uint8_t *byte; /* Current byte */
|
|
uint8_t bit; /* Current bit */
|
|
volatile int result; /* Exchange result */
|
|
};
|
|
|
|
/* 1-Wire device, Instance */
|
|
|
|
struct stm32_1wire_inst_s
|
|
{
|
|
const struct onewire_ops_s *ops; /* Standard 1-Wire operations */
|
|
struct stm32_1wire_priv_s *priv; /* Common driver private data structure */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static inline uint32_t stm32_1wire_in(struct stm32_1wire_priv_s *priv, int offset);
|
|
static inline void stm32_1wire_out(struct stm32_1wire_priv_s *priv, int offset, uint32_t value);
|
|
static int stm32_1wire_recv(struct stm32_1wire_priv_s *priv);
|
|
static void stm32_1wire_send(struct stm32_1wire_priv_s *priv, int ch);
|
|
static void stm32_1wire_set_baud(struct stm32_1wire_priv_s *priv);
|
|
static void stm32_1wire_set_apb_clock(struct stm32_1wire_priv_s *priv, bool on);
|
|
static int stm32_1wire_init(FAR struct stm32_1wire_priv_s *priv);
|
|
static int stm32_1wire_deinit(FAR struct stm32_1wire_priv_s *priv);
|
|
static inline void stm32_1wire_sem_init(FAR struct stm32_1wire_priv_s *priv);
|
|
static inline void stm32_1wire_sem_destroy(FAR struct stm32_1wire_priv_s *priv);
|
|
static inline void stm32_1wire_sem_wait(FAR struct stm32_1wire_priv_s *priv);
|
|
static inline void stm32_1wire_sem_post(FAR struct stm32_1wire_priv_s *priv);
|
|
static int stm32_1wire_process(struct stm32_1wire_priv_s *priv,
|
|
FAR const struct stm32_1wire_msg_s *msgs, int count);
|
|
static int stm32_1wire_isr(int irq, void *context, void *arg);
|
|
static int stm32_1wire_reset(FAR struct onewire_dev_s *dev);
|
|
static int stm32_1wire_write(FAR struct onewire_dev_s *dev,
|
|
const uint8_t *buffer, int buflen);
|
|
static int stm32_1wire_read(FAR struct onewire_dev_s *dev, uint8_t *buffer,
|
|
int buflen);
|
|
static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset,
|
|
const uint8_t *txbuffer, int txbuflen,
|
|
uint8_t *rxbuffer, int rxbuflen);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/* 1-Wire device structures */
|
|
|
|
#ifdef CONFIG_STM32_USART1_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire1_config =
|
|
{
|
|
.usartbase = STM32_USART1_BASE,
|
|
.apbclock = STM32_PCLK2_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_USART1_TX),
|
|
.irq = STM32_IRQ_USART1,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire1_priv =
|
|
{
|
|
.config = &stm32_1wire1_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_USART2_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire2_config =
|
|
{
|
|
.usartbase = STM32_USART2_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_USART2_TX),
|
|
.irq = STM32_IRQ_USART2,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire2_priv =
|
|
{
|
|
.config = &stm32_1wire2_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_USART3_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire3_config =
|
|
{
|
|
.usartbase = STM32_USART3_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_USART3_TX),
|
|
.irq = STM32_IRQ_USART3,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire3_priv =
|
|
{
|
|
.config = &stm32_1wire3_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_UART4_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire4_config =
|
|
{
|
|
.usartbase = STM32_UART4_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_UART4_TX),
|
|
.irq = STM32_IRQ_UART4,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire4_priv =
|
|
{
|
|
.config = &stm32_1wire4_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_UART5_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire5_config =
|
|
{
|
|
.usartbase = STM32_UART5_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_UART5_TX),
|
|
.irq = STM32_IRQ_UART5,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire5_priv =
|
|
{
|
|
.config = &stm32_1wire5_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_USART6_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire6_config =
|
|
{
|
|
.usartbase = STM32_USART6_BASE,
|
|
.apbclock = STM32_PCLK2_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_USART6_TX),
|
|
.irq = STM32_IRQ_USART6,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire6_priv =
|
|
{
|
|
.config = &stm32_1wire6_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_UART7_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire7_config =
|
|
{
|
|
.usartbase = STM32_UART7_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_UART7_TX),
|
|
.irq = STM32_IRQ_UART7,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire7_priv =
|
|
{
|
|
.config = &stm32_1wire7_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_STM32_UART8_1WIREDRIVER
|
|
|
|
static const struct stm32_1wire_config_s stm32_1wire8_config =
|
|
{
|
|
.usartbase = STM32_UART8_BASE,
|
|
.apbclock = STM32_PCLK1_FREQUENCY,
|
|
.data_pin = PIN_OPENDRAIN(GPIO_UART8_TX),
|
|
.irq = STM32_IRQ_UART8,
|
|
};
|
|
|
|
static struct stm32_1wire_priv_s stm32_1wire8_priv =
|
|
{
|
|
.config = &stm32_1wire8_config,
|
|
.refs = 0,
|
|
.msgs = NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
/* Device Structures, Instantiation */
|
|
|
|
static const struct onewire_ops_s stm32_1wire_ops =
|
|
{
|
|
.reset = stm32_1wire_reset,
|
|
.write = stm32_1wire_write,
|
|
.read = stm32_1wire_read,
|
|
.exchange = stm32_1wire_exchange
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_in
|
|
****************************************************************************/
|
|
|
|
static inline uint32_t stm32_1wire_in(struct stm32_1wire_priv_s *priv,
|
|
int offset)
|
|
{
|
|
return getreg32(priv->config->usartbase + offset);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_out
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_1wire_out(struct stm32_1wire_priv_s *priv,
|
|
int offset, uint32_t value)
|
|
{
|
|
putreg32(value, priv->config->usartbase + offset);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_recv
|
|
*
|
|
* Description:
|
|
* This method will recv one byte on the USART
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_recv(struct stm32_1wire_priv_s *priv)
|
|
{
|
|
return stm32_1wire_in(priv, STM32_USART_RDR_OFFSET) & 0xff;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_send
|
|
*
|
|
* Description:
|
|
* This method will send one byte on the USART
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_1wire_send(struct stm32_1wire_priv_s *priv, int ch)
|
|
{
|
|
stm32_1wire_out(priv, STM32_USART_TDR_OFFSET, (uint32_t)(ch & 0xff));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_set_baud
|
|
*
|
|
* Description:
|
|
* Set the serial line baud.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_1wire_set_baud(struct stm32_1wire_priv_s *priv)
|
|
{
|
|
#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX)
|
|
/* This first implementation is for U[S]ARTs that support oversampling
|
|
* by 8 in additional to the standard oversampling by 16.
|
|
*/
|
|
|
|
uint32_t usartdiv8;
|
|
uint32_t cr1;
|
|
uint32_t brr;
|
|
|
|
/* In case of oversampling by 8, the equation is:
|
|
*
|
|
* baud = 2 * fCK / usartdiv8
|
|
* usartdiv8 = 2 * fCK / baud
|
|
*/
|
|
|
|
usartdiv8 = ((priv->config->apbclock << 1) + (priv->baud >> 1)) / priv->baud;
|
|
|
|
/* Baud rate for standard USART (SPI mode included):
|
|
*
|
|
* In case of oversampling by 16, the equation is:
|
|
* baud = fCK / usartdiv16
|
|
* usartdiv16 = fCK / baud
|
|
* = 2 * usartdiv8
|
|
*/
|
|
|
|
/* Use oversamply by 8 only if the divisor is small. But what is small? */
|
|
|
|
cr1 = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET);
|
|
if (usartdiv8 > 100)
|
|
{
|
|
/* Use usartdiv16 */
|
|
|
|
brr = (usartdiv8 + 1) >> 1;
|
|
|
|
/* Clear oversampling by 8 to enable oversampling by 16 */
|
|
|
|
cr1 &= ~USART_CR1_OVER8;
|
|
}
|
|
else
|
|
{
|
|
DEBUGASSERT(usartdiv8 >= 8);
|
|
|
|
/* Perform mysterious operations on bits 0-3 */
|
|
|
|
brr = ((usartdiv8 & 0xfff0) | ((usartdiv8 & 0x000f) >> 1));
|
|
|
|
/* Set oversampling by 8 */
|
|
|
|
cr1 |= USART_CR1_OVER8;
|
|
}
|
|
|
|
stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, cr1);
|
|
stm32_1wire_out(priv, STM32_USART_BRR_OFFSET, brr);
|
|
|
|
#else
|
|
|
|
/* This second implementation is for U[S]ARTs that support fractional
|
|
* dividers.
|
|
*/
|
|
|
|
uint32_t usartdiv32;
|
|
uint32_t mantissa;
|
|
uint32_t fraction;
|
|
uint32_t brr;
|
|
|
|
/* Configure the USART Baud Rate. The baud rate for the receiver and
|
|
* transmitter (Rx and Tx) are both set to the same value as programmed
|
|
* in the Mantissa and Fraction values of USARTDIV.
|
|
*
|
|
* baud = fCK / (16 * usartdiv)
|
|
* usartdiv = fCK / (16 * baud)
|
|
*
|
|
* Where fCK is the input clock to the peripheral (PCLK1 for USART2, 3, 4, 5
|
|
* or PCLK2 for USART1)
|
|
*
|
|
* First calculate (NOTE: all stand baud values are even so dividing by two
|
|
* does not lose precision):
|
|
*
|
|
* usartdiv32 = 32 * usartdiv = fCK / (baud/2)
|
|
*/
|
|
|
|
usartdiv32 = priv->config->apbclock / (priv->baud >> 1);
|
|
|
|
/* The mantissa part is then */
|
|
|
|
mantissa = usartdiv32 >> 5;
|
|
brr = mantissa << USART_BRR_MANT_SHIFT;
|
|
|
|
/* The fractional remainder (with rounding) */
|
|
|
|
fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1;
|
|
brr |= fraction << USART_BRR_FRAC_SHIFT;
|
|
stm32_1wire_out(priv, STM32_USART_BRR_OFFSET, brr);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_set_apb_clock
|
|
*
|
|
* Description:
|
|
* Enable or disable APB clock for the USART peripheral
|
|
*
|
|
* Input parameters:
|
|
* priv - A reference to the 1-Wire driver state structure
|
|
* on - Enable clock if 'on' is 'true' and disable if 'false'
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_1wire_set_apb_clock(struct stm32_1wire_priv_s *priv,
|
|
bool on)
|
|
{
|
|
const struct stm32_1wire_config_s *config = priv->config;
|
|
uint32_t rcc_en;
|
|
uint32_t regaddr;
|
|
|
|
/* Determine which USART to configure */
|
|
|
|
switch (config->usartbase)
|
|
{
|
|
default:
|
|
return;
|
|
|
|
#ifdef CONFIG_STM32_USART1_1WIREDRIVER
|
|
case STM32_USART1_BASE:
|
|
rcc_en = RCC_APB2ENR_USART1EN;
|
|
regaddr = STM32_RCC_APB2ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART2_1WIREDRIVER
|
|
case STM32_USART2_BASE:
|
|
rcc_en = RCC_APB1ENR_USART2EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART3_1WIREDRIVER
|
|
case STM32_USART3_BASE:
|
|
rcc_en = RCC_APB1ENR_USART3EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART4_1WIREDRIVER
|
|
case STM32_UART4_BASE:
|
|
rcc_en = RCC_APB1ENR_UART4EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART5_1WIREDRIVER
|
|
case STM32_UART5_BASE:
|
|
rcc_en = RCC_APB1ENR_UART5EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART6_1WIREDRIVER
|
|
case STM32_USART6_BASE:
|
|
rcc_en = RCC_APB2ENR_USART6EN;
|
|
regaddr = STM32_RCC_APB2ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART7_1WIREDRIVER
|
|
case STM32_UART7_BASE:
|
|
rcc_en = RCC_APB1ENR_UART7EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART8_1WIREDRIVER
|
|
case STM32_UART8_BASE:
|
|
rcc_en = RCC_APB1ENR_UART8EN;
|
|
regaddr = STM32_RCC_APB1ENR;
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
/* Enable/disable APB 1/2 clock for USART */
|
|
|
|
if (on)
|
|
{
|
|
modifyreg32(regaddr, 0, rcc_en);
|
|
}
|
|
else
|
|
{
|
|
modifyreg32(regaddr, rcc_en, 0);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_init
|
|
*
|
|
* Description:
|
|
* Setup the 1-Wire hardware, ready for operation with defaults
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_init(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
const struct stm32_1wire_config_s *config = priv->config;
|
|
uint32_t regval;
|
|
int ret;
|
|
|
|
/* Enable USART APB1/2 clock */
|
|
|
|
stm32_1wire_set_apb_clock(priv, true);
|
|
|
|
/* Configure CR2 */
|
|
/* Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */
|
|
/* Set LBDIE */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR2_OFFSET);
|
|
regval &= ~(USART_CR2_STOP_MASK | USART_CR2_CLKEN | USART_CR2_CPOL |
|
|
USART_CR2_CPHA | USART_CR2_LBCL | USART_CR2_LBDIE);
|
|
regval |= USART_CR2_LBDIE;
|
|
stm32_1wire_out(priv, STM32_USART_CR2_OFFSET, regval);
|
|
|
|
/* Configure CR1 */
|
|
/* Clear TE, REm, all interrupt enable bits, PCE, PS and M */
|
|
/* Set RXNEIE */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET);
|
|
regval &= ~(USART_CR1_TE | USART_CR1_RE | USART_CR1_ALLINTS |
|
|
USART_CR1_PCE | USART_CR1_PS | USART_CR1_M);
|
|
regval |= USART_CR1_RXNEIE;
|
|
stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval);
|
|
|
|
/* Configure CR3 */
|
|
/* Clear CTSE, RTSE, and all interrupt enable bits */
|
|
/* Set ONEBIT, HDSEL and EIE */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR3_OFFSET);
|
|
regval &= ~(USART_CR3_CTSIE | USART_CR3_CTSE | USART_CR3_RTSE | USART_CR3_EIE);
|
|
regval |= (USART_CR3_ONEBIT | USART_CR3_HDSEL | USART_CR3_EIE);
|
|
stm32_1wire_out(priv, STM32_USART_CR3_OFFSET, regval);
|
|
|
|
/* Set baud rate */
|
|
|
|
priv->baud = RESET_BAUD;
|
|
stm32_1wire_set_baud(priv);
|
|
|
|
/* Enable Rx, Tx, and the USART */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET);
|
|
regval |= (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
|
|
stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval);
|
|
|
|
/* Configure pins for USART use */
|
|
|
|
stm32_configgpio(config->data_pin);
|
|
|
|
ret = irq_attach(config->irq, stm32_1wire_isr, priv);
|
|
if (ret == OK)
|
|
{
|
|
up_enable_irq(config->irq);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_deinit
|
|
*
|
|
* Description:
|
|
* Shutdown the 1-Wire hardware
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_deinit(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
const struct stm32_1wire_config_s *config = priv->config;
|
|
uint32_t regval;
|
|
|
|
up_disable_irq(config->irq);
|
|
irq_detach(config->irq);
|
|
|
|
/* Unconfigure GPIO pins */
|
|
|
|
stm32_unconfiggpio(config->data_pin);
|
|
|
|
/* Disable RXNEIE, Rx, Tx, and the USART */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR1_OFFSET);
|
|
regval &= ~(USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE);
|
|
stm32_1wire_out(priv, STM32_USART_CR1_OFFSET, regval);
|
|
|
|
/* Clear LBDIE */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR2_OFFSET);
|
|
regval &= ~USART_CR2_LBDIE;
|
|
stm32_1wire_out(priv, STM32_USART_CR2_OFFSET, regval);
|
|
|
|
/* Clear ONEBIT, HDSEL and EIE */
|
|
|
|
regval = stm32_1wire_in(priv, STM32_USART_CR3_OFFSET);
|
|
regval &= ~(USART_CR3_ONEBIT | USART_CR3_HDSEL | USART_CR3_EIE);
|
|
stm32_1wire_out(priv, STM32_USART_CR3_OFFSET, regval);
|
|
|
|
/* Disable USART APB1/2 clock */
|
|
|
|
stm32_1wire_set_apb_clock(priv, false);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_sem_init
|
|
*
|
|
* Description:
|
|
* Initialize semaphores
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_1wire_sem_init(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
nxsem_init(&priv->sem_excl, 0, 1);
|
|
nxsem_init(&priv->sem_isr, 0, 0);
|
|
|
|
/* The sem_isr semaphore is used for signaling and, hence, should not have
|
|
* priority inheritance enabled.
|
|
*/
|
|
|
|
nxsem_setprotocol(&priv->sem_isr, SEM_PRIO_NONE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_sem_destroy
|
|
*
|
|
* Description:
|
|
* Destroy semaphores.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_1wire_sem_destroy(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
nxsem_destroy(&priv->sem_excl);
|
|
nxsem_destroy(&priv->sem_isr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_sem_wait
|
|
*
|
|
* Description:
|
|
* Take the exclusive access, waiting as necessary
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_1wire_sem_wait(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
int ret;
|
|
|
|
do
|
|
{
|
|
/* Take the semaphore (perhaps waiting) */
|
|
|
|
ret = nxsem_wait(&priv->sem_excl);
|
|
|
|
/* The only case that an error should occur here is if the wait was
|
|
* awakened by a signal.
|
|
*/
|
|
|
|
DEBUGASSERT(ret == OK || ret == -EINTR);
|
|
}
|
|
while (ret == -EINTR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_sem_post
|
|
*
|
|
* Description:
|
|
* Release the mutual exclusion semaphore
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void stm32_1wire_sem_post(FAR struct stm32_1wire_priv_s *priv)
|
|
{
|
|
nxsem_post(&priv->sem_excl);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_exec
|
|
*
|
|
* Description:
|
|
* Execute 1-Wire task
|
|
****************************************************************************/
|
|
static int stm32_1wire_process(struct stm32_1wire_priv_s *priv,
|
|
FAR const struct stm32_1wire_msg_s *msgs,
|
|
int count)
|
|
{
|
|
irqstate_t irqs;
|
|
struct timespec abstime;
|
|
int indx;
|
|
int ret;
|
|
|
|
/* Lock out other clients */
|
|
|
|
stm32_1wire_sem_wait(priv);
|
|
|
|
priv->result = ERROR;
|
|
|
|
for (indx = 0; indx < count; indx++)
|
|
{
|
|
switch (msgs[indx].task)
|
|
{
|
|
case ONEWIRETASK_NONE:
|
|
priv->result = OK;
|
|
break;
|
|
|
|
case ONEWIRETASK_RESET:
|
|
/* Set baud rate */
|
|
|
|
priv->baud = RESET_BAUD;
|
|
stm32_1wire_set_baud(priv);
|
|
|
|
/* Atomic */
|
|
|
|
irqs = enter_critical_section();
|
|
priv->msgs = &msgs[indx];
|
|
stm32_1wire_send(priv, RESET_TX);
|
|
leave_critical_section(irqs);
|
|
|
|
/* Wait. Break on timeout if TX line closed to GND */
|
|
|
|
clock_gettime(CLOCK_REALTIME, &abstime);
|
|
abstime.tv_sec += BUS_TIMEOUT;
|
|
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
|
|
break;
|
|
|
|
case ONEWIRETASK_WRITE:
|
|
/* Set baud rate */
|
|
|
|
priv->baud = TIMESLOT_BAUD;
|
|
stm32_1wire_set_baud(priv);
|
|
|
|
/* Atomic */
|
|
|
|
irqs = enter_critical_section();
|
|
priv->msgs = &msgs[indx];
|
|
priv->byte = priv->msgs->buffer;
|
|
priv->bit = 0;
|
|
stm32_1wire_send(priv, (*priv->byte & (1 << priv->bit)) ? WRITE_TX1 : WRITE_TX0);
|
|
leave_critical_section(irqs);
|
|
|
|
/* Wait. Break on timeout if TX line closed to GND */
|
|
|
|
clock_gettime(CLOCK_REALTIME, &abstime);
|
|
abstime.tv_sec += BUS_TIMEOUT;
|
|
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
|
|
break;
|
|
|
|
case ONEWIRETASK_READ:
|
|
/* Set baud rate */
|
|
|
|
priv->baud = TIMESLOT_BAUD;
|
|
stm32_1wire_set_baud(priv);
|
|
|
|
/* Atomic */
|
|
|
|
irqs = enter_critical_section();
|
|
priv->msgs = &msgs[indx];
|
|
priv->byte = priv->msgs->buffer;
|
|
priv->bit = 0;
|
|
stm32_1wire_send(priv, READ_TX);
|
|
leave_critical_section(irqs);
|
|
|
|
/* Wait. Break on timeout if TX line closed to GND */
|
|
|
|
clock_gettime(CLOCK_REALTIME, &abstime);
|
|
abstime.tv_sec += BUS_TIMEOUT;
|
|
(void)nxsem_timedwait(&priv->sem_isr, &abstime);
|
|
break;
|
|
}
|
|
|
|
if (priv->result != OK) /* break if error */
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Atomic */
|
|
|
|
irqs = enter_critical_section();
|
|
priv->msgs = NULL;
|
|
ret = priv->result;
|
|
leave_critical_section(irqs);
|
|
|
|
/* Release the port for re-use by other clients */
|
|
|
|
stm32_1wire_sem_post(priv);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_isr
|
|
*
|
|
* Description:
|
|
* Common Interrupt Service Routine
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_isr(int irq, void *context, void *arg)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = (struct stm32_1wire_priv_s *)arg;
|
|
uint32_t sr;
|
|
uint32_t dr;
|
|
|
|
DEBUGASSERT(priv != NULL);
|
|
|
|
/* Get the masked USART status word. */
|
|
|
|
sr = stm32_1wire_in(priv, STM32_USART_SR_OFFSET);
|
|
|
|
/* Receive loop */
|
|
|
|
if ((sr & USART_SR_RXNE) != 0)
|
|
{
|
|
dr = stm32_1wire_recv(priv);
|
|
|
|
if (priv->msgs != NULL)
|
|
{
|
|
switch (priv->msgs->task)
|
|
{
|
|
case ONEWIRETASK_NONE:
|
|
break;
|
|
|
|
case ONEWIRETASK_RESET:
|
|
priv->msgs = NULL;
|
|
priv->result = (dr != RESET_TX) ? OK : -ENODEV; /* if read RESET_TX then no slave */
|
|
nxsem_post(&priv->sem_isr);
|
|
break;
|
|
|
|
case ONEWIRETASK_WRITE:
|
|
if (++priv->bit >= 8)
|
|
{
|
|
priv->bit = 0;
|
|
if (++priv->byte >= (priv->msgs->buffer + priv->msgs->buflen)) /* Done? */
|
|
{
|
|
priv->msgs = NULL;
|
|
priv->result = OK;
|
|
nxsem_post(&priv->sem_isr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Send next bit */
|
|
|
|
stm32_1wire_send(priv, (*priv->byte & (1 << priv->bit)) ? WRITE_TX1 : WRITE_TX0);
|
|
break;
|
|
|
|
case ONEWIRETASK_READ:
|
|
if (dr == READ_RX1)
|
|
{
|
|
*priv->byte |= (1 << priv->bit);
|
|
}
|
|
else
|
|
{
|
|
*priv->byte &= ~(1 << priv->bit);
|
|
}
|
|
|
|
if (++priv->bit >= 8)
|
|
{
|
|
priv->bit = 0;
|
|
if (++priv->byte >= (priv->msgs->buffer + priv->msgs->buflen)) /* Done? */
|
|
{
|
|
priv->msgs = NULL;
|
|
priv->result = OK;
|
|
nxsem_post(&priv->sem_isr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Recv next bit */
|
|
|
|
stm32_1wire_send(priv, READ_TX);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Bounce check. */
|
|
|
|
if ((sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE)) != 0)
|
|
{
|
|
#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX)
|
|
/* These errors are cleared by writing the corresponding bit to the
|
|
* interrupt clear register (ICR).
|
|
*/
|
|
|
|
stm32_1wire_out(priv, STM32_USART_ICR_OFFSET,
|
|
(USART_ICR_NCF | USART_ICR_ORECF | USART_ICR_FECF));
|
|
#else
|
|
/* If an error occurs, read from DR to clear the error (data has
|
|
* been lost). If ORE is set along with RXNE then it tells you
|
|
* that the byte *after* the one in the data register has been
|
|
* lost, but the data register value is correct. That case will
|
|
* be handled above if interrupts are enabled. Otherwise, that
|
|
* good byte will be lost.
|
|
*/
|
|
|
|
(void)stm32_1wire_recv(priv);
|
|
#endif
|
|
|
|
if (priv->msgs != NULL)
|
|
{
|
|
priv->msgs = NULL;
|
|
priv->result = ERROR;
|
|
nxsem_post(&priv->sem_isr);
|
|
}
|
|
}
|
|
|
|
/* Bounce check. LIN break detection */
|
|
|
|
if ((sr & USART_SR_LBD) != 0)
|
|
{
|
|
sr &= ~USART_SR_LBD;
|
|
stm32_1wire_out(priv, STM32_USART_SR_OFFSET, sr);
|
|
|
|
if (priv->msgs != NULL)
|
|
{
|
|
priv->msgs = NULL;
|
|
priv->result = ERROR;
|
|
nxsem_post(&priv->sem_isr);
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_reset
|
|
*
|
|
* Description:
|
|
* 1-Wire reset pulse and presence detect.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_reset(FAR struct onewire_dev_s *dev)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv;
|
|
const struct stm32_1wire_msg_s msgs[1] =
|
|
{
|
|
[0].task = ONEWIRETASK_RESET
|
|
};
|
|
|
|
return stm32_1wire_process(priv, msgs, 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_write
|
|
*
|
|
* Description:
|
|
* Write 1-Wire data
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_write(FAR struct onewire_dev_s *dev, const uint8_t *buffer,
|
|
int buflen)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv;
|
|
const struct stm32_1wire_msg_s msgs[1] =
|
|
{
|
|
[0].task = ONEWIRETASK_WRITE,
|
|
[0].buffer = (uint8_t *)buffer,
|
|
[0].buflen = buflen
|
|
};
|
|
|
|
return stm32_1wire_process(priv, msgs, 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_read
|
|
*
|
|
* Description:
|
|
* Read 1-Wire data
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_read(FAR struct onewire_dev_s *dev, uint8_t *buffer, int buflen)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv;
|
|
const struct stm32_1wire_msg_s msgs[1] =
|
|
{
|
|
[0].task = ONEWIRETASK_READ,
|
|
[0].buffer = buffer,
|
|
[0].buflen = buflen
|
|
};
|
|
|
|
return stm32_1wire_process(priv, msgs, 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wire_exchange
|
|
*
|
|
* Description:
|
|
* 1-Wire reset pulse and presence detect,
|
|
* Write 1-Wire data,
|
|
* Read 1-Wire data
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_1wire_exchange(FAR struct onewire_dev_s *dev, bool reset,
|
|
const uint8_t *txbuffer, int txbuflen,
|
|
uint8_t *rxbuffer, int rxbuflen)
|
|
|
|
{
|
|
int result = ERROR;
|
|
struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv;
|
|
|
|
if (reset)
|
|
{
|
|
const struct stm32_1wire_msg_s msgs[3] =
|
|
{
|
|
[0].task = ONEWIRETASK_RESET,
|
|
|
|
[1].task = ONEWIRETASK_WRITE,
|
|
[1].buffer = (uint8_t *)txbuffer,
|
|
[1].buflen = txbuflen,
|
|
|
|
[2].task = ONEWIRETASK_READ,
|
|
[2].buffer = rxbuffer,
|
|
[2].buflen = rxbuflen
|
|
};
|
|
|
|
result = stm32_1wire_process(priv, msgs, 3);
|
|
}
|
|
else
|
|
{
|
|
const struct stm32_1wire_msg_s msgs[2] =
|
|
{
|
|
[0].task = ONEWIRETASK_WRITE,
|
|
[0].buffer = (uint8_t *)txbuffer,
|
|
[0].buflen = txbuflen,
|
|
|
|
[1].task = ONEWIRETASK_READ,
|
|
[1].buffer = rxbuffer,
|
|
[1].buflen = rxbuflen
|
|
};
|
|
|
|
result = stm32_1wire_process(priv, msgs, 2);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wireinitialize
|
|
*
|
|
* Description:
|
|
* Initialize the selected 1-Wire port. And return a unique instance of struct
|
|
* struct onewire_dev_s. This function may be called to obtain multiple
|
|
* instances of the interface, each of which may be set up with a
|
|
* different frequency and slave address.
|
|
*
|
|
* Input Parameter:
|
|
* Port number (for hardware that has multiple 1-Wire interfaces)
|
|
*
|
|
* Returned Value:
|
|
* Valid 1-Wire device structure reference on succcess; a NULL on failure
|
|
*
|
|
****************************************************************************/
|
|
|
|
FAR struct onewire_dev_s *stm32_1wireinitialize(int port)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = NULL; /* Private data of device with multiple instances */
|
|
struct stm32_1wire_inst_s *inst = NULL; /* Device, single instance */
|
|
int irqs;
|
|
|
|
/* Get 1-Wire private structure */
|
|
|
|
switch (port)
|
|
{
|
|
#ifdef CONFIG_STM32_USART1_1WIREDRIVER
|
|
case 1:
|
|
priv = &stm32_1wire1_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART2_1WIREDRIVER
|
|
case 2:
|
|
priv = &stm32_1wire2_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART3_1WIREDRIVER
|
|
case 3:
|
|
priv = &stm32_1wire3_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART4_1WIREDRIVER
|
|
case 4:
|
|
priv = &stm32_1wire4_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART5_1WIREDRIVER
|
|
case 5:
|
|
priv = &stm32_1wire5_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_USART6_1WIREDRIVER
|
|
case 6:
|
|
priv = &stm32_1wire6_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART7_1WIREDRIVER
|
|
case 7:
|
|
priv = &stm32_1wire7_priv;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_UART8_1WIREDRIVER
|
|
case 8:
|
|
priv = &stm32_1wire8_priv;
|
|
break;
|
|
#endif
|
|
default:
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate instance */
|
|
|
|
if (!(inst = kmm_malloc(sizeof(struct stm32_1wire_inst_s))))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Initialize instance */
|
|
|
|
inst->ops = &stm32_1wire_ops;
|
|
inst->priv = priv;
|
|
|
|
/* Initialize private data for the first time, increment reference count,
|
|
* power-up hardware and configure GPIOs.
|
|
*/
|
|
|
|
irqs = enter_critical_section();
|
|
|
|
if (priv->refs++ == 0)
|
|
{
|
|
stm32_1wire_sem_init(priv);
|
|
stm32_1wire_init(priv);
|
|
}
|
|
|
|
leave_critical_section(irqs);
|
|
return (struct onewire_dev_s *)inst;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_1wireuninitialize
|
|
*
|
|
* Description:
|
|
* De-initialize the selected 1-Wire port, and power down the device.
|
|
*
|
|
* Input Parameter:
|
|
* Device structure as returned by the stm32_1wireinitialize()
|
|
*
|
|
* Returned Value:
|
|
* OK on success, ERROR when internal reference count mismatch or dev
|
|
* points to invalid hardware device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int stm32_1wireuninitialize(FAR struct onewire_dev_s *dev)
|
|
{
|
|
struct stm32_1wire_priv_s *priv = ((struct stm32_1wire_inst_s *)dev)->priv;
|
|
int irqs;
|
|
|
|
ASSERT(dev);
|
|
|
|
/* Decrement reference count and check for underflow */
|
|
|
|
if (priv->refs == 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
irqs = enter_critical_section();
|
|
|
|
if (--priv->refs)
|
|
{
|
|
leave_critical_section(irqs);
|
|
kmm_free(priv);
|
|
return OK;
|
|
}
|
|
|
|
leave_critical_section(irqs);
|
|
|
|
/* Disable power and other HW resource (GPIO's) */
|
|
|
|
stm32_1wire_deinit(priv);
|
|
|
|
/* Release unused resources */
|
|
|
|
stm32_1wire_sem_destroy(priv);
|
|
|
|
/* Free instance */
|
|
|
|
kmm_free(dev);
|
|
return OK;
|
|
}
|
|
|
|
#endif /* HAVE_1WIREDRIVER */
|