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+
10 #include <linux/serial_reg.h>
11 #include <linux/sizes.h>
12 #include <linux/errno.h>
13 #include <dm/device.h>
18 * Note: Register map is slightly different from that of 16550.
20 struct uniphier_serial
{
21 u32 rx
; /* In: Receive buffer */
22 #define tx rx /* Out: Transmit buffer */
23 u32 ier
; /* Interrupt Enable Register */
24 u32 iir
; /* In: Interrupt ID Register */
25 u32 char_fcr
; /* Charactor / FIFO Control Register */
26 u32 lcr_mcr
; /* Line/Modem Control Register */
28 #define LCR_MASK (0xff << (LCR_SHIFT))
29 u32 lsr
; /* In: Line Status Register */
30 u32 msr
; /* In: Modem Status Register */
33 u32 dlr
; /* Divisor Latch Register */
36 struct uniphier_serial_private_data
{
37 struct uniphier_serial __iomem
*membase
;
41 #define uniphier_serial_port(dev) \
42 ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
44 static int uniphier_serial_setbrg(struct udevice
*dev
, int baudrate
)
46 struct uniphier_serial_private_data
*priv
= dev_get_priv(dev
);
47 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
48 const unsigned int mode_x_div
= 16;
51 divisor
= DIV_ROUND_CLOSEST(priv
->uartclk
, mode_x_div
* baudrate
);
53 writel(divisor
, &port
->dlr
);
58 static int uniphier_serial_getc(struct udevice
*dev
)
60 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
62 if (!(readl(&port
->lsr
) & UART_LSR_DR
))
65 return readl(&port
->rx
);
68 static int uniphier_serial_putc(struct udevice
*dev
, const char c
)
70 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
72 if (!(readl(&port
->lsr
) & UART_LSR_THRE
))
80 static int uniphier_serial_pending(struct udevice
*dev
, bool input
)
82 struct uniphier_serial __iomem
*port
= uniphier_serial_port(dev
);
85 return readl(&port
->lsr
) & UART_LSR_DR
;
87 return !(readl(&port
->lsr
) & UART_LSR_THRE
);
90 static int uniphier_serial_probe(struct udevice
*dev
)
92 DECLARE_GLOBAL_DATA_PTR
;
93 struct uniphier_serial_private_data
*priv
= dev_get_priv(dev
);
94 struct uniphier_serial __iomem
*port
;
98 base
= dev_get_addr(dev
);
99 if (base
== FDT_ADDR_T_NONE
)
102 port
= devm_ioremap(dev
, base
, SZ_64
);
106 priv
->membase
= port
;
108 priv
->uartclk
= fdtdec_get_int(gd
->fdt_blob
, dev
->of_offset
,
109 "clock-frequency", 0);
111 tmp
= readl(&port
->lcr_mcr
);
113 tmp
|= UART_LCR_WLEN8
<< LCR_SHIFT
;
114 writel(tmp
, &port
->lcr_mcr
);
119 static const struct udevice_id uniphier_uart_of_match
[] = {
120 { .compatible
= "socionext,uniphier-uart" },
124 static const struct dm_serial_ops uniphier_serial_ops
= {
125 .setbrg
= uniphier_serial_setbrg
,
126 .getc
= uniphier_serial_getc
,
127 .putc
= uniphier_serial_putc
,
128 .pending
= uniphier_serial_pending
,
131 U_BOOT_DRIVER(uniphier_serial
) = {
132 .name
= "uniphier-uart",
134 .of_match
= uniphier_uart_of_match
,
135 .probe
= uniphier_serial_probe
,
136 .priv_auto_alloc_size
= sizeof(struct uniphier_serial_private_data
),
137 .ops
= &uniphier_serial_ops
,