Advertisement
Cheros

s32_linflexuart.c

Apr 1st, 2020
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.34 KB | None | 0 0
  1. /*
  2.  * xen/drivers/char/s32linflex-uart.c
  3.  *
  4.  * Driver for NXP Linflex UART.
  5.  *
  6.  * Peter van der Perk <peter.vander.perk@nxp.com>
  7.  * Copyright 2018 NXP
  8.  *
  9.  */
  10.  
  11. #include <xen/config.h>
  12. #include <xen/console.h>
  13. #include <xen/errno.h>
  14. #include <xen/serial.h>
  15. #include <xen/init.h>
  16. #include <xen/irq.h>
  17. #include <xen/mm.h>
  18. #include <asm/device.h>
  19. #include <asm/s32linflex-uart.h>
  20. #include <asm/io.h>
  21.  
  22. #define s32linflex_uart_readl(uart, off)       \
  23.             readl((uart)->regs + (off))
  24. #define s32linflex_uart_writel(uart, off, val) \
  25.             writel((val), (uart)->regs + (off))
  26. #define s32linflex_uart_readb(uart, off)       \
  27.             readb((uart)->regs + (off))
  28. #define s32linflex_uart_writeb(uart, off, val) \
  29.             writeb((val), (uart)->regs + (off))
  30.  
  31. #define LIN_CLK_FREQ    (66666667)  /* LIN_CLK freq taken from Linux */
  32. #define LIN_BAUDRATE    (115200)    /* LINFlex UART Baud Rate  */
  33. #define LIN_DATABITS    (8)     /* LINFlex UART Data Bits  */
  34. #define LIN_STOPBITS    (1)     /* LINFlex UART Stop Bits  */
  35. #define LIN_PARITYNONE  (0)     /* LINFlex UART Parity None */
  36.  
  37. static struct s32linflex_uart {
  38.     unsigned int baud, clock_hz, data_bits, parity, stop_bits, fifo_size;
  39.     unsigned int irq;
  40.     char __iomem *regs;
  41.     struct irqaction irqaction;
  42.     struct vuart_info vuart;
  43. } s32_com = {0};
  44.  
  45.  
  46. static void __init s32linflex_uart_init_preirq(struct serial_port *port)
  47. {
  48.     struct s32linflex_uart *uart = port->uart;
  49.     u32 ctrl;
  50.  
  51.     u32 clk;
  52.     u32 ibr, fbr;
  53.  
  54.     /* set the Linflex in master mode amd activate by-pass filter */
  55.     ctrl = LINCR1_BF | LINCR1_MME;
  56.     s32linflex_uart_writel(uart, LINCR1, ctrl);
  57.  
  58.     /* init mode */
  59.     ctrl |= LINCR1_INIT;
  60.     s32linflex_uart_writel(uart, LINCR1, ctrl);
  61.  
  62.     /* waiting for init mode entry */
  63.     while ((s32linflex_uart_readl(uart, LINSR) & LINSR_LINS_MASK) !=
  64.         LINSR_LINS_INITMODE)
  65.         ;
  66.  
  67.     /* set UART bit to allow writing other bits */
  68.     s32linflex_uart_writel(uart, UARTCR, UARTCR_UART);
  69.  
  70.     /* provide data bits, parity, stop bit, etc */
  71.     clk = uart->clock_hz;
  72.  
  73.     ibr = (u32) (clk / (16 * (uart)->baud));
  74.     fbr = (u32) (clk % (16 * (uart)->baud)) / (uart->baud);
  75.  
  76.     s32linflex_uart_writel(uart, LINIBRR, ibr);
  77.     s32linflex_uart_writel(uart, LINFBRR, fbr);
  78.  
  79.     /* 8 bit data, no parity, Tx and Rx enabled, UART mode */
  80.     s32linflex_uart_writel(uart, UARTCR, UARTCR_PC1 | UARTCR_RXEN |
  81.         UARTCR_TXEN | UARTCR_PC0 | UARTCR_WL0 | UARTCR_UART);
  82.  
  83.     ctrl = s32linflex_uart_readl(uart, LINCR1);
  84.     ctrl &= ~LINCR1_INIT;
  85.  
  86.     /* end init mode */
  87.     s32linflex_uart_writel(uart, LINCR1, ctrl);
  88. }
  89.  
  90. static void s32linflex_uart_interrupt(int irq, void *data,
  91.                     struct cpu_user_regs *regs)
  92. {
  93.     struct serial_port *port = data;
  94.     struct s32linflex_uart *uart = port->uart;
  95.     unsigned int sts;
  96.  
  97.     sts = s32linflex_uart_readl(uart, UARTSR);
  98.  
  99.     if (sts & UARTSR_DRF)
  100.         serial_rx_interrupt(port, regs);
  101.  
  102.     if (sts & UARTSR_DTF)
  103.         serial_tx_interrupt(port, regs);
  104. }
  105.  
  106. static void __init s32linflex_uart_init_postirq(struct serial_port *port)
  107. {
  108.     struct s32linflex_uart *uart = port->uart;
  109.     unsigned int temp;
  110.  
  111.     uart->irqaction.handler = s32linflex_uart_interrupt;
  112.     uart->irqaction.name = "s32linflex_uart";
  113.     uart->irqaction.dev_id = port;
  114.  
  115.     temp = s32linflex_uart_readl(uart, LINIER);
  116.     temp |= (LINIER_DRIE | LINIER_DTIE);
  117.     s32linflex_uart_writel(uart, LINIER, temp);
  118. }
  119.  
  120. static void s32linflex_uart_suspend(struct serial_port *port)
  121. {
  122.     BUG();
  123. }
  124.  
  125. static void s32linflex_uart_resume(struct serial_port *port)
  126. {
  127.     BUG();
  128. }
  129.  
  130.  
  131. static int s32linflex_uart_tx_ready(struct serial_port *port)
  132. {
  133.     struct s32linflex_uart *uart = port->uart;
  134.  
  135.     return (s32linflex_uart_readb(uart, UARTSR) & UARTSR_DTF) ? 1 : 0;
  136. }
  137.  
  138. static void s32linflex_uart_putc(struct serial_port *port, char c)
  139. {
  140.     struct s32linflex_uart *uart = port->uart;
  141.  
  142.     s32linflex_uart_writeb(uart, BDRL, c);
  143.  
  144.     s32linflex_uart_writeb(uart, UARTSR,
  145.         (s32linflex_uart_readb(uart, UARTSR) | UARTSR_DTF));
  146. }
  147.  
  148. static int s32linflex_uart_getc(struct serial_port *port, char *pc)
  149. {
  150.     struct s32linflex_uart *uart = port->uart;
  151.     int ch;
  152.  
  153.     if (!(s32linflex_uart_readb(uart, UARTSR) & UARTSR_DRF))
  154.         return 0;
  155.  
  156.     if (!(s32linflex_uart_readl(uart, UARTSR) & UARTSR_RMB))
  157.         return 0;
  158.  
  159.     ch = s32linflex_uart_readl(uart, BDRM);
  160.     *pc = ch & 0xff;
  161.  
  162.     s32linflex_uart_writeb(uart, UARTSR,
  163.         (s32linflex_uart_readb(uart, UARTSR) |
  164.             (UARTSR_DRF | UARTSR_RMB)));
  165.  
  166.  
  167.     return 1;
  168. }
  169.  
  170. static int __init s32linflex_uart_irq(struct serial_port *port)
  171. {
  172.     struct s32linflex_uart *uart = port->uart;
  173.  
  174.     return ((uart->irq > 0) ? uart->irq : -1);
  175. }
  176.  
  177.  
  178. static const struct vuart_info *s32linflex_uart_vuart_info(
  179.     struct serial_port *port)
  180. {
  181.     struct s32linflex_uart *uart = port->uart;
  182.  
  183.     return &uart->vuart;
  184. }
  185.  
  186. static void s32linflex_uart_start_tx(struct serial_port *port)
  187. {
  188.     struct s32linflex_uart *uart = port->uart;
  189.     unsigned long temp;
  190.  
  191.     temp = s32linflex_uart_readl(uart, LINIER);
  192.     s32linflex_uart_writel(uart, LINIER, temp | LINIER_DTIE);
  193. }
  194.  
  195. static void s32linflex_uart_stop_tx(struct serial_port *port)
  196. {
  197.     struct s32linflex_uart *uart = port->uart;
  198.     unsigned long temp;
  199.  
  200.     temp = s32linflex_uart_readl(uart, LINIER);
  201.     temp &= ~(LINIER_DTIE);
  202.     s32linflex_uart_writel(uart, LINIER, temp);
  203. }
  204.  
  205.  
  206. static struct uart_driver __read_mostly s32linflex_uart_driver = {
  207.     .init_preirq = s32linflex_uart_init_preirq,
  208.     .init_postirq = s32linflex_uart_init_postirq,
  209.     .endboot = NULL,
  210.     .suspend = s32linflex_uart_suspend,
  211.     .resume = s32linflex_uart_resume,
  212.     .tx_ready = s32linflex_uart_tx_ready,
  213.     .putc = s32linflex_uart_putc,
  214.     .getc = s32linflex_uart_getc,
  215.     .irq = s32linflex_uart_irq,
  216.     .start_tx = s32linflex_uart_start_tx,
  217.     .stop_tx = s32linflex_uart_stop_tx,
  218.     .vuart_info = s32linflex_uart_vuart_info,
  219. };
  220.  
  221. static int __init s32linflex_uart_init(struct dt_device_node *dev,
  222.                     const void *data)
  223. {
  224.     const char *config = data;
  225.     struct s32linflex_uart *uart;
  226.     int res;
  227.     u64 addr, size;
  228.  
  229.     if (config && strcmp(config, ""))
  230.         printk(KERN_WARNING "WARNING: UART configuration is not supported\n");
  231.  
  232.     uart = &s32_com;
  233.  
  234.     uart->clock_hz = LIN_CLK_FREQ;
  235.     uart->baud = LIN_BAUDRATE;
  236.     uart->data_bits = LIN_DATABITS;
  237.     uart->parity = LIN_PARITYNONE;
  238.     uart->stop_bits = LIN_STOPBITS;
  239.  
  240.     res = dt_device_get_address(dev, 0, &addr, &size);
  241.     if (res) {
  242.         printk(KERN_ERR "s32linflex-uart: Unable to retrieve the base address of the UART\n");
  243.         return res;
  244.     }
  245.  
  246.     res = platform_get_irq(dev, 0);
  247.     if (res < 0) {
  248.         printk(KERN_ERR "s32linflex-uart: Unable to retrieve the IRQ\n");
  249.         return -EINVAL;
  250.     }
  251.     uart->irq = res;
  252.  
  253.     uart->regs = ioremap_nocache(addr, size);
  254.     if (!uart->regs) {
  255.         printk(KERN_ERR "s32linflex-uart: Unable to map the UART memory\n");
  256.         return -ENOMEM;
  257.     }
  258.  
  259.     uart->vuart.base_addr = addr;
  260.     uart->vuart.size = size;
  261.     uart->vuart.data_off = BDRL;
  262.     uart->vuart.status_off = UARTSR;
  263.     uart->vuart.status = UARTSR_DTF;
  264.  
  265.     /* Register with generic serial driver */
  266.     serial_register_uart(SERHND_DTUART, &s32linflex_uart_driver, uart);
  267.  
  268.     dt_device_set_used_by(dev, DOMID_XEN);
  269.  
  270.     return 0;
  271. }
  272.  
  273. static const struct dt_device_match s32linflex_uart_dt_compat[] __initconst = {
  274.     DT_MATCH_COMPATIBLE("fsl,s32-linflexuart"),
  275.     {},
  276. };
  277.  
  278. DT_DEVICE_START(s32linflex_uart, "NXP Linflex UART", DEVICE_SERIAL)
  279.     .dt_match = s32linflex_uart_dt_compat,
  280.     .init = s32linflex_uart_init,
  281. DT_DEVICE_END
  282. /*
  283.  * Local variables:
  284.  * mode: C
  285.  * c-file-style: "BSD"
  286.  * c-basic-offset: 4
  287.  * indent-tabs-mode: nil
  288.  * End:
  289.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement