| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (C) 2022 Stefan Bosch <stefan_b@posteo.net> |
| */ |
| |
| #include <dm.h> |
| #include <asm/arch/clk.h> |
| #include <asm/arch/reset.h> |
| #include <linux/delay.h> |
| |
| #include <dm/platform_data/serial_pl01x.h> |
| #include <serial.h> |
| #include "serial_pl01x_internal.h" |
| |
| int s5p4418_pl011_serial_probe(struct udevice *dev) |
| { |
| struct pl01x_serial_plat *plat = dev_get_plat(dev); |
| struct clk *nx_clk; |
| ulong rate_act; |
| char uart_clk_name[10]; |
| int uart_num = -1; |
| int rst_id, ret; |
| |
| if (!plat->skip_init) { |
| uart_num = dev->seq_; |
| rst_id = RESET_ID_UART0 + uart_num; |
| |
| if (uart_num < 0 || rst_id > RESET_ID_UART5) { |
| /* invalid UART-number */ |
| debug("%s: sequence/uart number %d is invalid!\n", __func__, uart_num); |
| return -ENODEV; |
| } |
| |
| sprintf(uart_clk_name, "nx-uart.%d", uart_num); |
| nx_clk = clk_get(uart_clk_name); |
| if (!nx_clk) { |
| debug("%s: clk_get('%s') failed!\n", __func__, uart_clk_name); |
| return -ENODEV; |
| } |
| |
| /* wait to make sure all pending characters have been sent */ |
| mdelay(100); |
| } |
| |
| /* |
| * Note: Unless !plat->skip_init, the UART is disabled here, so printf() |
| * or debug() must not be used until pl01x_serial_setbrg() has been called |
| * (enables the UART). Otherwise u-boot is hanging! |
| */ |
| ret = pl01x_serial_probe(dev); |
| if (ret) |
| return ret; |
| |
| if (!plat->skip_init) { |
| /* do reset UART */ |
| nx_rstcon_setrst(rst_id, RSTCON_ASSERT); |
| udelay(10); |
| nx_rstcon_setrst(rst_id, RSTCON_NEGATE); |
| udelay(10); |
| clk_disable(nx_clk); |
| |
| rate_act = clk_set_rate(nx_clk, plat->clock); |
| clk_enable(nx_clk); |
| |
| plat->clock = rate_act; |
| } |
| |
| return 0; |
| } |
| |
| static const struct dm_serial_ops s5p4418_pl011_serial_ops = { |
| .putc = pl01x_serial_putc, |
| .pending = pl01x_serial_pending, |
| .getc = pl01x_serial_getc, |
| .setbrg = pl01x_serial_setbrg, |
| }; |
| |
| static const struct udevice_id s5p4418_pl011_serial_id[] = { |
| {.compatible = "nexell,s5p4418-pl011", .data = TYPE_PL011}, |
| {} |
| }; |
| |
| U_BOOT_DRIVER(s5p4418_pl011_uart) = { |
| .name = "s5p4418_pl011", |
| .id = UCLASS_SERIAL, |
| .of_match = of_match_ptr(s5p4418_pl011_serial_id), |
| .of_to_plat = of_match_ptr(pl01x_serial_of_to_plat), |
| .plat_auto = sizeof(struct pl01x_serial_plat), |
| .probe = s5p4418_pl011_serial_probe, |
| .ops = &s5p4418_pl011_serial_ops, |
| .flags = DM_FLAG_PRE_RELOC, |
| .priv_auto = sizeof(struct pl01x_priv), |
| }; |