mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-11 18:35:28 +00:00
stm32: USB Power Delivery physical layer
Implementation of the physical layer for USB Power Delivery communication using the STM32 chip. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=none TEST=none Change-Id: I2a4adeef572b97a284bf52ab9d14d23246c56d18 Reviewed-on: https://chromium-review.googlesource.com/189867 Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
d4c939e9ee
commit
828c1a384a
@@ -37,3 +37,4 @@ chip-$(HAS_TASK_POWERLED)+=power_led.o
|
||||
chip-$(CONFIG_FLASH)+=flash-$(FLASH_FAMILY).o
|
||||
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
|
||||
chip-$(CONFIG_PWM)+=pwm.o
|
||||
chip-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_phy.o
|
||||
|
||||
@@ -670,6 +670,7 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
|
||||
#define STM32_SPI_CR1_MSTR (1 << 2)
|
||||
#define STM32_SPI_CR2_RXDMAEN (1 << 0)
|
||||
#define STM32_SPI_CR2_TXDMAEN (1 << 1)
|
||||
#define STM32_SPI_CR2_DATASIZE(n) (((n) - 1) << 8)
|
||||
|
||||
/* --- Debug --- */
|
||||
|
||||
|
||||
495
chip/stm32/usb_pd_phy.c
Normal file
495
chip/stm32/usb_pd_phy.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "dma.h"
|
||||
#include "gpio.h"
|
||||
#include "hwtimer.h"
|
||||
#include "hooks.h"
|
||||
#include "registers.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "usb_pd.h"
|
||||
#include "usb_pd_config.h"
|
||||
|
||||
#ifdef CONFIG_COMMON_RUNTIME
|
||||
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
|
||||
#else
|
||||
#define CPRINTF(format, args...)
|
||||
#endif
|
||||
|
||||
#define PD_DATARATE 300000 /* Hz */
|
||||
|
||||
/*
|
||||
* Maximum size of a Power Delivery packet (in bits on the wire) :
|
||||
* 16-bit header + 0..7 32-bit data objects (+ 4b5b encoding)
|
||||
* 64-bit preamble + SOP (4x 5b) + message in 4b5b + 32-bit CRC + EOP (1x 5b)
|
||||
* = 64 + 4*5 + 16 * 5/4 + 7 * 32 * 5/4 + 32 * 5/4 + 5
|
||||
*/
|
||||
#define PD_BIT_LEN 429
|
||||
|
||||
#define PD_MAX_RAW_SIZE (PD_BIT_LEN*2)
|
||||
|
||||
/* maximum number of consecutive similar bits with Biphase Mark Coding */
|
||||
#define MAX_BITS 2
|
||||
|
||||
/* alternating bit sequence used for packet preamble : 00 10 11 01 00 .. */
|
||||
#define PD_PREAMBLE 0xB4B4B4B4 /* starts with 0, ends with 1 */
|
||||
|
||||
#define TX_CLOCK_DIV ((clock_get_freq() / (2*PD_DATARATE)))
|
||||
|
||||
/* threshold for 1 300-khz period */
|
||||
#define PERIOD 4
|
||||
#define NB_PERIOD(from, to) ((((to) - (from) + (PERIOD/2)) & 0xFF) / PERIOD)
|
||||
#define PERIOD_THRESHOLD ((PERIOD + 2*PERIOD) / 2)
|
||||
|
||||
/* Timers used for TX and RX clocking */
|
||||
#define TIM_TX TIM_CLOCK_PD_TX
|
||||
#define TIM_RX TIM_CLOCK_PD_RX
|
||||
|
||||
#include "crc.h"
|
||||
|
||||
/* samples for the PD messages */
|
||||
static uint32_t raw_samples[DIV_ROUND_UP(PD_MAX_RAW_SIZE, sizeof(uint32_t))];
|
||||
|
||||
/* state of the bit decoder */
|
||||
static int d_toggle;
|
||||
static int d_lastlen;
|
||||
static uint32_t d_last;
|
||||
|
||||
void *pd_init_dequeue(void)
|
||||
{
|
||||
/* preamble ends with 1 */
|
||||
d_toggle = 0;
|
||||
d_last = 0;
|
||||
d_lastlen = 0;
|
||||
|
||||
return raw_samples;
|
||||
}
|
||||
|
||||
static int wait_bits(int nb)
|
||||
{
|
||||
int avail;
|
||||
stm32_dma_chan_t *rx = dma_get_channel(DMAC_TIM_RX);
|
||||
|
||||
avail = dma_bytes_done(rx, PD_MAX_RAW_SIZE);
|
||||
if (avail < nb) { /* no received yet ... */
|
||||
timestamp_t deadline = get_time();
|
||||
deadline.val += 4 * MAX_BITS * (nb - avail);
|
||||
while ((dma_bytes_done(rx, PD_MAX_RAW_SIZE) < nb)
|
||||
&& get_time().val < deadline.val)
|
||||
; /* optimized for latency, not CPU usage ... */
|
||||
if (dma_bytes_done(rx, PD_MAX_RAW_SIZE) < nb) {
|
||||
CPRINTF("TMOUT RX %d/%d\n",
|
||||
dma_bytes_done(rx, PD_MAX_RAW_SIZE), nb);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
int pd_dequeue_bits(void *ctxt, int off, int len, uint32_t *val)
|
||||
{
|
||||
int w;
|
||||
uint8_t cnt = 0xff;
|
||||
uint8_t *samples = ctxt;
|
||||
|
||||
while ((d_lastlen < len) && (off < PD_MAX_RAW_SIZE - 1)) {
|
||||
w = wait_bits(off + 2);
|
||||
if (w < 0)
|
||||
goto stream_err;
|
||||
cnt = samples[off] - samples[off-1];
|
||||
if (!cnt || (cnt > 3*PERIOD))
|
||||
goto stream_err;
|
||||
off++;
|
||||
if (cnt <= PERIOD_THRESHOLD) {
|
||||
/*
|
||||
w = wait_bits(off + 1);
|
||||
if (w < 0)
|
||||
goto stream_err;
|
||||
*/
|
||||
cnt = samples[off] - samples[off-1];
|
||||
if (cnt > PERIOD_THRESHOLD)
|
||||
goto stream_err;
|
||||
off++;
|
||||
}
|
||||
|
||||
/* enqueue the bit of the last period */
|
||||
d_last = (d_last >> 1)
|
||||
| (cnt <= PERIOD_THRESHOLD ? 0x80000000 : 0);
|
||||
d_lastlen++;
|
||||
}
|
||||
if (off < PD_MAX_RAW_SIZE) {
|
||||
*val = (d_last << (d_lastlen - len)) >> (32 - len);
|
||||
d_lastlen -= len;
|
||||
return off;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
stream_err:
|
||||
CPRINTF("Invalid %d @%d\n", cnt, off);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pd_find_preamble(void *ctxt)
|
||||
{
|
||||
int bit;
|
||||
uint8_t *vals = ctxt;
|
||||
|
||||
/*
|
||||
* Detect preamble
|
||||
* Alternate 1-period 1-period & 2-period.
|
||||
*/
|
||||
uint32_t all = 0;
|
||||
stm32_dma_chan_t *rx = dma_get_channel(DMAC_TIM_RX);
|
||||
|
||||
for (bit = 1; bit < PD_MAX_RAW_SIZE - 1; bit++) {
|
||||
uint8_t cnt;
|
||||
/* wait if the bit is not received yet ... */
|
||||
if (PD_MAX_RAW_SIZE - rx->cndtr < bit + 1) {
|
||||
while ((PD_MAX_RAW_SIZE - rx->cndtr < bit + 1) &&
|
||||
!(STM32_TIM_SR(TIM_RX) & 4))
|
||||
;
|
||||
if (STM32_TIM_SR(TIM_RX) & 4) {
|
||||
CPRINTF("TMOUT RX %d/%d\n",
|
||||
PD_MAX_RAW_SIZE - rx->cndtr, bit);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cnt = vals[bit] - vals[bit-1];
|
||||
all = (all >> 1) | (cnt <= PERIOD_THRESHOLD ? 1 << 31 : 0);
|
||||
if (all == 0x36db6db6)
|
||||
return bit - 1; /* should be SYNC-1 */
|
||||
if (all == 0xF33F3F3F)
|
||||
return -2; /* got HARD-RESET */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int b_toggle;
|
||||
|
||||
int pd_write_preamble(void *ctxt)
|
||||
{
|
||||
uint32_t *msg = ctxt;
|
||||
|
||||
/* 64-bit x2 preamble */
|
||||
msg[0] = PD_PREAMBLE;
|
||||
msg[1] = PD_PREAMBLE;
|
||||
msg[2] = PD_PREAMBLE;
|
||||
msg[3] = PD_PREAMBLE;
|
||||
b_toggle = 0x3FF; /* preamble ends with 1 */
|
||||
return 2*64;
|
||||
}
|
||||
|
||||
int pd_write_sym(void *ctxt, int bit_off, uint32_t val10)
|
||||
{
|
||||
uint32_t *msg = ctxt;
|
||||
int word_idx = bit_off / 32;
|
||||
int bit_idx = bit_off % 32;
|
||||
uint32_t val = b_toggle ^ val10;
|
||||
b_toggle = val & 0x200 ? 0x3FF : 0;
|
||||
if (bit_idx <= 22) {
|
||||
if (bit_idx == 0)
|
||||
msg[word_idx] = 0;
|
||||
msg[word_idx] |= val << bit_idx;
|
||||
} else {
|
||||
msg[word_idx] |= val << bit_idx;
|
||||
msg[word_idx+1] = val >> (32 - bit_idx);
|
||||
/* side effect: clear the new word when starting it */
|
||||
}
|
||||
return bit_off + 5*2;
|
||||
}
|
||||
|
||||
int pd_write_last_edge(void *ctxt, int bit_off)
|
||||
{
|
||||
uint32_t *msg = ctxt;
|
||||
int word_idx = bit_off / 32;
|
||||
int bit_idx = bit_off % 32;
|
||||
|
||||
if (bit_idx == 0)
|
||||
msg[word_idx] = 0;
|
||||
if (!b_toggle /* last bit was 0 */) {
|
||||
/* transition to 1, then 0 */
|
||||
msg[word_idx] |= 1 << bit_idx;
|
||||
}
|
||||
/* ensure that the trailer is 0 */
|
||||
msg[word_idx+1] = 0;
|
||||
|
||||
return bit_off + 2;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMMON_RUNTIME
|
||||
void pd_dump_packet(void *ctxt, const char *msg)
|
||||
{
|
||||
uint8_t *vals = ctxt;
|
||||
int bit;
|
||||
|
||||
CPRINTF("ERR %s:\n000:- ", msg);
|
||||
/* Packet debug output */
|
||||
for (bit = 1; bit < PD_MAX_RAW_SIZE; bit++) {
|
||||
int cnt = NB_PERIOD(vals[bit-1], vals[bit]);
|
||||
if ((bit & 31) == 0)
|
||||
CPRINTF("\n%03d:", bit);
|
||||
CPRINTF("%1d ", cnt);
|
||||
}
|
||||
CPRINTF("><\n");
|
||||
cflush();
|
||||
for (bit = 0; bit < PD_MAX_RAW_SIZE; bit++) {
|
||||
if ((bit & 31) == 0)
|
||||
CPRINTF("\n%03d:", bit);
|
||||
CPRINTF("%02x ", vals[bit]);
|
||||
}
|
||||
CPRINTF("||\n");
|
||||
cflush();
|
||||
}
|
||||
#endif /* CONFIG_COMMON_RUNTIME */
|
||||
|
||||
/* --- SPI TX operation --- */
|
||||
|
||||
static const struct dma_option dma_tx_option = {
|
||||
DMAC_SPI_TX, (void *)&SPI_REGS->dr,
|
||||
STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT
|
||||
};
|
||||
|
||||
void pd_start_tx(void *ctxt, int bit_len)
|
||||
{
|
||||
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX);
|
||||
|
||||
/* update DMA configuration */
|
||||
dma_prepare_tx(&dma_tx_option, DIV_ROUND_UP(bit_len, 8), ctxt);
|
||||
/* Flush data in write buffer so that DMA can get the lastest data */
|
||||
asm volatile("dmb;");
|
||||
/* Kick off the DMA to send the data */
|
||||
dma_go(tx);
|
||||
|
||||
/* disable RX detection interrupt */
|
||||
pd_rx_disable_monitoring();
|
||||
/*
|
||||
* Drive the CC line from the TX block :
|
||||
* - set the low level reference.
|
||||
* - put SPI function on TX pin.
|
||||
*/
|
||||
pd_tx_enable();
|
||||
|
||||
/* Start counting at 300Khz*/
|
||||
STM32_TIM_CR1(TIM_TX) |= 1;
|
||||
}
|
||||
|
||||
void pd_tx_done(void)
|
||||
{
|
||||
stm32_spi_regs_t *spi = SPI_REGS;
|
||||
|
||||
dma_wait(DMAC_SPI_TX);
|
||||
/* wait for real end of transmission */
|
||||
#ifdef CHIP_FAMILY_STM32F0
|
||||
while ((spi->sr & (3<<11)))
|
||||
; /* wait for TX FIFO empty */
|
||||
#else
|
||||
while (!(spi->sr & (1<<1)))
|
||||
; /* wait for TXE == 1 */
|
||||
#endif
|
||||
while (spi->sr & (1<<7))
|
||||
; /* wait for BSY == 0 */
|
||||
/* ensure that we are not pushing out junk */
|
||||
*(uint8_t *)&spi->dr = 0;
|
||||
/* Stop counting */
|
||||
STM32_TIM_CR1(TIM_TX) &= ~1;
|
||||
/* clear tranfer flag */
|
||||
dma_clear_isr(DMAC_SPI_TX);
|
||||
/* put TX pins and reference in Hi-Z */
|
||||
pd_tx_disable();
|
||||
}
|
||||
|
||||
/* --- RX operation using comparator linked to timer --- */
|
||||
|
||||
static const struct dma_option dma_tim_option = {
|
||||
DMAC_TIM_RX, (void *)&STM32_TIM_CCRx(TIM_RX, TIM_CCR_IDX),
|
||||
STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_16_BIT,
|
||||
};
|
||||
|
||||
void pd_rx_start(void)
|
||||
{
|
||||
/* start sampling the edges on the CC line using the RX timer */
|
||||
dma_start_rx(&dma_tim_option, PD_MAX_RAW_SIZE, raw_samples);
|
||||
/* enable TIM2 DMA requests */
|
||||
STM32_TIM_EGR(TIM_RX) = 0x0001; /* reset counter / reload PSC */;
|
||||
STM32_TIM_SR(TIM_RX) = 0; /* clear overflows */
|
||||
STM32_TIM_CR1(TIM_RX) |= 1;
|
||||
}
|
||||
|
||||
void pd_rx_complete(void)
|
||||
{
|
||||
/* stop stampling TIM2 */
|
||||
STM32_TIM_CR1(TIM_RX) &= ~1;
|
||||
/* stop DMA */
|
||||
dma_disable(DMAC_TIM_RX);
|
||||
}
|
||||
|
||||
void pd_rx_enable_monitoring(void)
|
||||
{
|
||||
/* clear comparator external interrupt */
|
||||
STM32_EXTI_PR = 1 << EXTI_COMP;
|
||||
/* clean up older comparator event */
|
||||
task_clear_pending_irq(IRQ_COMP);
|
||||
/* re-enable comparator interrupt to detect packets */
|
||||
task_enable_irq(IRQ_COMP);
|
||||
}
|
||||
|
||||
void pd_rx_disable_monitoring(void)
|
||||
{
|
||||
/* stop monitoring RX during sampling */
|
||||
task_disable_irq(IRQ_COMP);
|
||||
/* clear comparator external interrupt */
|
||||
STM32_EXTI_PR = 1 << EXTI_COMP;
|
||||
}
|
||||
|
||||
/* detect an edge on the PD RX pin */
|
||||
void pd_rx_handler(void)
|
||||
{
|
||||
/* start sampling */
|
||||
pd_rx_start();
|
||||
/* ignore the comparator IRQ until we are done with current message */
|
||||
pd_rx_disable_monitoring();
|
||||
/* trigger the analysis in the task */
|
||||
pd_rx_event();
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_COMP, pd_rx_handler, 1);
|
||||
|
||||
/* --- Startup initialization --- */
|
||||
void *pd_hw_init(void)
|
||||
{
|
||||
stm32_spi_regs_t *spi = SPI_REGS;
|
||||
|
||||
/* set 40 MHz pin speed on communication pins */
|
||||
pd_set_pins_speed();
|
||||
|
||||
/* --- SPI init --- */
|
||||
|
||||
/* Enable clocks to SPI module */
|
||||
spi_enable_clock();
|
||||
|
||||
/* Initialize TX pins and put them in Hi-Z */
|
||||
pd_tx_init();
|
||||
|
||||
/* Enable Tx DMA for our first transaction */
|
||||
spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8);
|
||||
|
||||
/* Enable the salve SPI: LSB first, force NSS, TX only */
|
||||
spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST
|
||||
| STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE
|
||||
| STM32_SPI_CR1_BIDIOE;
|
||||
|
||||
/* configure TX DMA */
|
||||
dma_prepare_tx(&dma_tx_option, PD_MAX_RAW_SIZE, raw_samples);
|
||||
|
||||
/* --- set the TX timer with updates at 600KHz (BMC frequency) --- */
|
||||
__hw_timer_enable_clock(TIM_TX, 1);
|
||||
/* Timer configuration */
|
||||
STM32_TIM_CR1(TIM_TX) = 0x0000;
|
||||
STM32_TIM_CR2(TIM_TX) = 0x0000;
|
||||
STM32_TIM_DIER(TIM_TX) = 0x0000;
|
||||
/* Auto-reload value : 600000 Khz overflow */
|
||||
STM32_TIM_ARR(TIM_TX) = TX_CLOCK_DIV;
|
||||
/* 50% duty cycle on the output */
|
||||
STM32_TIM_CCR1(TIM_TX) = STM32_TIM_ARR(TIM_TX) / 2;
|
||||
/* Timer CH1 output configuration */
|
||||
STM32_TIM_CCMR1(TIM_TX) = (6 << 4) | (1 << 3);
|
||||
STM32_TIM_CCER(TIM_TX) = 1;
|
||||
STM32_TIM_BDTR(TIM_TX) = 0x8000;
|
||||
/* set prescaler to /1 */
|
||||
STM32_TIM_PSC(TIM_TX) = 0;
|
||||
/* Reload the pre-scaler and reset the counter */
|
||||
STM32_TIM_EGR(TIM_TX) = 0x0001;
|
||||
|
||||
/* --- set counter for RX timing : 2.4Mhz rate, free-running --- */
|
||||
__hw_timer_enable_clock(TIM_RX, 1);
|
||||
/* Timer configuration */
|
||||
STM32_TIM_CR1(TIM_RX) = 0x0000;
|
||||
STM32_TIM_CR2(TIM_RX) = 0x0000;
|
||||
STM32_TIM_DIER(TIM_RX) = 0x0000;
|
||||
/* Auto-reload value : 16-bit free running counter */
|
||||
STM32_TIM_ARR(TIM_RX) = 0xFFFF;
|
||||
/* Timeout for message receive : 2.7ms */
|
||||
STM32_TIM_CCR2(TIM_RX) = clock_get_freq() / (RX_CLOCK_DIV + 1)
|
||||
* 27 / 10000 /* 2.7 ms */;
|
||||
/* Timer ICx input configuration */
|
||||
#if TIM_CCR_IDX == 1
|
||||
STM32_TIM_CCMR1(TIM_RX) = TIM_CCR_CS << 0;
|
||||
#elif TIM_CCR_IDX == 4
|
||||
STM32_TIM_CCMR2(TIM_RX) = TIM_CCR_CS << 8;
|
||||
#else
|
||||
#error Unsupported RX timer capture input
|
||||
#endif
|
||||
STM32_TIM_CCER(TIM_RX) = 0xB << ((TIM_CCR_IDX - 1) * 4);
|
||||
/* configure DMA request on CCRx update */
|
||||
STM32_TIM_DIER(TIM_RX) |= 1 << (8 + TIM_CCR_IDX); /* CCxDE */;
|
||||
/* set prescaler to /26 (F=1.2Mhz, T=0.8us) */
|
||||
STM32_TIM_PSC(TIM_RX) = RX_CLOCK_DIV;
|
||||
/* Reload the pre-scaler and reset the counter */
|
||||
STM32_TIM_EGR(TIM_RX) = 0x0001 | (1 << TIM_CCR_IDX) /* clear CCRx */;
|
||||
/* clear update event from reloading */
|
||||
STM32_TIM_SR(TIM_RX) = 0;
|
||||
|
||||
/* --- DAC configuration for comparator at 850mV --- */
|
||||
#ifdef CONFIG_PD_USE_DAC_AS_REF
|
||||
/* Enable DAC interface clock. */
|
||||
STM32_RCC_APB1ENR |= (1 << 29);
|
||||
/* set voltage Vout=0.850V (Vref = 3.0V) */
|
||||
STM32_DAC_DHR12RD = 850 * 4096 / 3000;
|
||||
/* Start DAC channel 1 */
|
||||
STM32_DAC_CR = STM32_DAC_CR_EN1;
|
||||
#endif
|
||||
|
||||
/* --- COMP2 as comparator for RX vs Vmid = 850mV --- */
|
||||
#ifdef CONFIG_USB_PD_INTERNAL_COMP
|
||||
#if defined(CHIP_FAMILY_STM32F0)
|
||||
/* 40 MHz pin speed on PA0 and PA4 */
|
||||
STM32_GPIO_OSPEEDR(GPIO_A) |= 0x303;
|
||||
/* turn on COMP/SYSCFG */
|
||||
STM32_RCC_APB2ENR |= 1 << 0;
|
||||
/* currently in hi-speed mode : TODO revisit later, INM = PA0(INM6) */
|
||||
STM32_COMP_CSR = STM32_COMP_CMP1EN | STM32_COMP_CMP1MODE_LSPEED |
|
||||
STM32_COMP_CMP1INSEL_INM6 |
|
||||
STM32_COMP_CMP1OUTSEL_TIM1_IC1 |
|
||||
STM32_COMP_CMP1HYST_HI;
|
||||
#elif defined(CHIP_FAMILY_STM32L)
|
||||
/* 40 MHz pin speed on PB4 */
|
||||
STM32_GPIO_OSPEEDR(GPIO_B) |= 0x300;
|
||||
|
||||
STM32_RCC_APB1ENR |= 1 << 31; /* turn on COMP */
|
||||
|
||||
STM32_COMP_CSR = STM32_COMP_OUTSEL_TIM2_IC4 | STM32_COMP_INSEL_DAC_OUT1
|
||||
| STM32_COMP_SPEED_FAST;
|
||||
/* route PB4 to COMP input2 through GR6_1 bit 4 (or PB5->GR6_2 bit 5) */
|
||||
STM32_RI_ASCR2 |= 1 << 4;
|
||||
#else
|
||||
#error Unsupported chip family
|
||||
#endif
|
||||
#endif /* CONFIG_USB_PD_INTERNAL_COMP */
|
||||
/* DBG */usleep(250000);
|
||||
/* comparator interrupt setup */
|
||||
EXTI_XTSR |= 1 << EXTI_COMP;
|
||||
STM32_EXTI_IMR |= 1 << EXTI_COMP;
|
||||
task_enable_irq(IRQ_COMP);
|
||||
|
||||
CPRINTF("USB PD initialized\n");
|
||||
return raw_samples;
|
||||
}
|
||||
|
||||
void pd_set_clock(int freq)
|
||||
{
|
||||
STM32_TIM_ARR(TIM_TX) = clock_get_freq() / (2*freq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
void pd_set_host_mode(int enable)
|
||||
{
|
||||
gpio_set_level(GPIO_CC_HOST, enable);
|
||||
}
|
||||
#endif /* CONFIG_USB_PD_DUAL_ROLE */
|
||||
Reference in New Issue
Block a user