2 * Copyright (C) 2012-2015 Panasonic Corporation
3 * Copyright (C) 2015-2016 Socionext Inc.
4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
6 * SPDX-License-Identifier: GPL-2.0+
12 #include <linux/serial_reg.h>
13 #include <linux/sizes.h>
14 #include <linux/errno.h>
19 * Note: Register map is slightly different from that of 16550.
21 struct uniphier_serial
{
22 u32 rx
; /* In: Receive buffer */
23 #define tx rx /* Out: Transmit buffer */
24 u32 ier
; /* Interrupt Enable Register */
25 u32 iir
; /* In: Interrupt ID Register */
26 u32 char_fcr
; /* Charactor / FIFO Control Register */
27 u32 lcr_mcr
; /* Line/Modem Control Register */
29 #define LCR_MASK (0xff << (LCR_SHIFT))
30 u32 lsr
; /* In: Line Status Register */
31 u32 msr
; /* In: Modem Status Register */
34 u32 dlr
; /* Divisor Latch Register */
37 struct uniphier_serial_private_data
{
38 struct uniphier_serial __iomem
*membase
;
42 #define uniphier_serial_port(dev) \
43 ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
45 static int uniphier_serial_setbrg(struct udevice
*dev
, int baudrate
)
47 struct uniphier_serial_private_data
*priv
= dev_get_priv(dev
);
48 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
49 const unsigned int mode_x_div
= 16;
52 divisor
= DIV_ROUND_CLOSEST(priv
->uartclk
, mode_x_div
* baudrate
);
54 writel(divisor
, &port
->dlr
);
59 static int uniphier_serial_getc(struct udevice
*dev
)
61 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
63 if (!(readl(&port
->lsr
) & UART_LSR_DR
))
66 return readl(&port
->rx
);
69 static int uniphier_serial_putc(struct udevice
*dev
, const char c
)
71 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
73 if (!(readl(&port
->lsr
) & UART_LSR_THRE
))
81 static int uniphier_serial_pending(struct udevice
*dev
, bool input
)
83 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
86 return readl(&port
->lsr
) & UART_LSR_DR
;
88 return !(readl(&port
->lsr
) & UART_LSR_THRE
);
91 static int uniphier_serial_probe(struct udevice
*dev
)
93 DECLARE_GLOBAL_DATA_PTR
;
94 struct uniphier_serial_private_data
*priv
= dev_get_priv(dev
);
95 struct uniphier_serial __iomem
*port
;
99 base
= devfdt_get_addr(dev
);
100 if (base
== FDT_ADDR_T_NONE
)
103 port
= devm_ioremap(dev
, base
, SZ_64
);
107 priv
->membase
= port
;
109 priv
->uartclk
= fdtdec_get_int(gd
->fdt_blob
, dev_of_offset(dev
),
110 "clock-frequency", 0);
112 tmp
= readl(&port
->lcr_mcr
);
114 tmp
|= UART_LCR_WLEN8
<< LCR_SHIFT
;
115 writel(tmp
, &port
->lcr_mcr
);
120 static const struct udevice_id uniphier_uart_of_match
[] = {
121 { .compatible
= "socionext,uniphier-uart" },
125 static const struct dm_serial_ops uniphier_serial_ops
= {
126 .setbrg
= uniphier_serial_setbrg
,
127 .getc
= uniphier_serial_getc
,
128 .putc
= uniphier_serial_putc
,
129 .pending
= uniphier_serial_pending
,
132 U_BOOT_DRIVER(uniphier_serial
) = {
133 .name
= "uniphier-uart",
135 .of_match
= uniphier_uart_of_match
,
136 .probe
= uniphier_serial_probe
,
137 .priv_auto_alloc_size
= sizeof(struct uniphier_serial_private_data
),
138 .ops
= &uniphier_serial_ops
,