Home | History | Annotate | Download | only in stm32f4xx
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <plat/inc/gpio.h>
     18 #include <plat/inc/usart.h>
     19 #include <plat/inc/pwr.h>
     20 #include <usart.h>
     21 #include <gpio.h>
     22 
     23 struct StmUsart {
     24   volatile uint16_t SR;
     25   uint8_t unused0[2];
     26   volatile uint16_t DR;
     27   uint8_t unused1[2];
     28   volatile uint16_t BRR;
     29   uint8_t unused2[2];
     30   volatile uint16_t CR1;
     31   uint8_t unused3[2];
     32   volatile uint16_t CR2;
     33   uint8_t unused4[2];
     34   volatile uint16_t CR3;
     35   uint8_t unused5[2];
     36   volatile uint16_t GTPR;
     37   uint8_t unused6[2];
     38 };
     39 
     40 static const uint32_t mUsartPorts[] = {
     41     USART1_BASE,
     42     USART2_BASE,
     43     USART3_BASE,
     44     UART4_BASE,
     45     UART5_BASE,
     46     USART6_BASE,
     47 };
     48 
     49 static const uint32_t mUsartPeriphs[] = {
     50     PERIPH_APB2_USART1,
     51     PERIPH_APB1_USART2,
     52     PERIPH_APB1_USART3,
     53     PERIPH_APB1_UART4,
     54     PERIPH_APB1_UART5,
     55     PERIPH_APB2_USART6,
     56 };
     57 
     58 static uint8_t mUsartBusses[] = {
     59     PERIPH_BUS_APB2,
     60     PERIPH_BUS_APB1,
     61     PERIPH_BUS_APB1,
     62     PERIPH_BUS_APB1,
     63     PERIPH_BUS_APB1,
     64     PERIPH_BUS_APB2,
     65 };
     66 
     67 static bool mUsartHasFlowControl[] = {
     68     true,
     69     true,
     70     true,
     71     false,
     72     false,
     73     true,
     74 };
     75 
     76 static enum StmGpioAltFunc mUsartAlt[] = {
     77     GPIO_AF_USART1,
     78     GPIO_AF_USART2,
     79     GPIO_AF00,
     80     GPIO_AF00,
     81     GPIO_AF00,
     82     GPIO_AF_USART6,
     83 };
     84 
     85 void usartOpen(struct usart* __restrict usart, UsartPort port,
     86                 uint32_t txGpioNum, uint32_t rxGpioNum,
     87                 uint32_t baud, UsartDataBitsCfg data_bits,
     88                 UsatStopBitsCfg stop_bits, UsartParityCfg parity,
     89                 UsartFlowControlCfg flow_control)
     90 {
     91     static const uint16_t stopBitsVals[] = {0x1000, 0x0000, 0x3000, 0x2000}; // indexed by UsatStopBitsCfg
     92     static const uint16_t wordLengthVals[] = {0x0000, 0x1000}; // indexed by UsartDataBitsCfg
     93     static const uint16_t parityVals[] = {0x0000, 0x0400, 0x0600}; // indexed by UsartParityCfg
     94     static const uint16_t flowCtrlVals[] = {0x0000, 0x0100, 0x0200, 0x0300}; // indexed by UsartFlowControlCfg
     95     struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit = --port];
     96     uint32_t baseClk, div, intPart, fraPart;
     97 
     98     /* configure tx/rx gpios */
     99 
    100     usart->rx = gpioRequest(rxGpioNum); /* rx */
    101     gpioConfigAlt(usart->rx, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_OUT_PUSH_PULL, mUsartAlt[port]);
    102     usart->tx = gpioRequest(txGpioNum); /* tx */
    103     gpioConfigAlt(usart->tx, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_OUT_PUSH_PULL, mUsartAlt[port]);
    104 
    105     /* enable clock */
    106     pwrUnitClock(mUsartBusses[port], mUsartPeriphs[port], true);
    107 
    108     /* sanity checks */
    109     if (!mUsartHasFlowControl[port])
    110         flow_control = USART_FLOW_CONTROL_NONE;
    111 
    112     /* basic config as required + oversample by 8, tx+rx on */
    113     block->CR2 = (block->CR2 &~ 0x3000) | stopBitsVals[stop_bits];
    114     block->CR1 = (block->CR1 &~ 0x1600) | wordLengthVals[data_bits] | parityVals[parity] | 0x800C;
    115     block->CR3 = (block->CR3 &~ 0x0300) | flowCtrlVals[flow_control];
    116 
    117     /* clocking calc */
    118     baseClk = pwrGetBusSpeed(mUsartBusses[port]);
    119     div = (baseClk * 25) / (baud * 2);
    120     intPart = div / 100;
    121     fraPart = div % 100;
    122 
    123     /* clocking munging */
    124     intPart = intPart << 4;
    125     fraPart = ((fraPart * 8 + 50) / 100) & 7;
    126     block->BRR = intPart | fraPart;
    127 
    128     /* enable */
    129     block->CR1 |= 0x2000;
    130 }
    131 
    132 void usartClose(const struct usart* __restrict usart)
    133 {
    134     struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
    135 
    136     /* Disable USART */
    137     block->CR1 &=~ 0x2000;
    138 
    139     /* Disable USART clock */
    140     pwrUnitClock(mUsartBusses[usart->unit], mUsartPeriphs[usart->unit], false);
    141 
    142     /* Release gpios */
    143     gpioRelease(usart->rx);
    144     gpioRelease(usart->tx);
    145 }
    146 
    147 void usartPutchar(const struct usart* __restrict usart, char c)
    148 {
    149     struct StmUsart *block = (struct StmUsart*)mUsartPorts[usart->unit];
    150 
    151     /* wait for ready */
    152     while (!(block->SR & 0x0080));
    153 
    154     /* send */
    155     block->DR = (uint8_t)c;
    156 }
    157