Stefan Bosch | 51f153c | 2022-12-18 12:20:49 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (C) 2022 Stefan Bosch <stefan_b@posteo.net> |
| 4 | */ |
| 5 | |
Stefan Bosch | 51f153c | 2022-12-18 12:20:49 +0000 | [diff] [blame] | 6 | #include <dm.h> |
| 7 | #include <asm/arch/clk.h> |
| 8 | #include <asm/arch/reset.h> |
| 9 | #include <linux/delay.h> |
| 10 | |
| 11 | #include <dm/platform_data/serial_pl01x.h> |
| 12 | #include <serial.h> |
| 13 | #include "serial_pl01x_internal.h" |
| 14 | |
| 15 | int s5p4418_pl011_serial_probe(struct udevice *dev) |
| 16 | { |
| 17 | struct pl01x_serial_plat *plat = dev_get_plat(dev); |
| 18 | struct clk *nx_clk; |
| 19 | ulong rate_act; |
| 20 | char uart_clk_name[10]; |
| 21 | int uart_num = -1; |
| 22 | int rst_id, ret; |
| 23 | |
| 24 | if (!plat->skip_init) { |
| 25 | uart_num = dev->seq_; |
| 26 | rst_id = RESET_ID_UART0 + uart_num; |
| 27 | |
| 28 | if (uart_num < 0 || rst_id > RESET_ID_UART5) { |
| 29 | /* invalid UART-number */ |
| 30 | debug("%s: sequence/uart number %d is invalid!\n", __func__, uart_num); |
| 31 | return -ENODEV; |
| 32 | } |
| 33 | |
| 34 | sprintf(uart_clk_name, "nx-uart.%d", uart_num); |
| 35 | nx_clk = clk_get(uart_clk_name); |
| 36 | if (!nx_clk) { |
| 37 | debug("%s: clk_get('%s') failed!\n", __func__, uart_clk_name); |
| 38 | return -ENODEV; |
| 39 | } |
| 40 | |
| 41 | /* wait to make sure all pending characters have been sent */ |
| 42 | mdelay(100); |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | * Note: Unless !plat->skip_init, the UART is disabled here, so printf() |
| 47 | * or debug() must not be used until pl01x_serial_setbrg() has been called |
| 48 | * (enables the UART). Otherwise u-boot is hanging! |
| 49 | */ |
| 50 | ret = pl01x_serial_probe(dev); |
| 51 | if (ret) |
| 52 | return ret; |
| 53 | |
| 54 | if (!plat->skip_init) { |
| 55 | /* do reset UART */ |
| 56 | nx_rstcon_setrst(rst_id, RSTCON_ASSERT); |
| 57 | udelay(10); |
| 58 | nx_rstcon_setrst(rst_id, RSTCON_NEGATE); |
| 59 | udelay(10); |
| 60 | clk_disable(nx_clk); |
| 61 | |
| 62 | rate_act = clk_set_rate(nx_clk, plat->clock); |
| 63 | clk_enable(nx_clk); |
| 64 | |
| 65 | plat->clock = rate_act; |
| 66 | } |
| 67 | |
| 68 | return 0; |
| 69 | } |
| 70 | |
| 71 | static const struct dm_serial_ops s5p4418_pl011_serial_ops = { |
| 72 | .putc = pl01x_serial_putc, |
| 73 | .pending = pl01x_serial_pending, |
| 74 | .getc = pl01x_serial_getc, |
| 75 | .setbrg = pl01x_serial_setbrg, |
| 76 | }; |
| 77 | |
| 78 | static const struct udevice_id s5p4418_pl011_serial_id[] = { |
| 79 | {.compatible = "nexell,s5p4418-pl011", .data = TYPE_PL011}, |
| 80 | {} |
| 81 | }; |
| 82 | |
| 83 | U_BOOT_DRIVER(s5p4418_pl011_uart) = { |
| 84 | .name = "s5p4418_pl011", |
| 85 | .id = UCLASS_SERIAL, |
| 86 | .of_match = of_match_ptr(s5p4418_pl011_serial_id), |
| 87 | .of_to_plat = of_match_ptr(pl01x_serial_of_to_plat), |
| 88 | .plat_auto = sizeof(struct pl01x_serial_plat), |
| 89 | .probe = s5p4418_pl011_serial_probe, |
| 90 | .ops = &s5p4418_pl011_serial_ops, |
| 91 | .flags = DM_FLAG_PRE_RELOC, |
| 92 | .priv_auto = sizeof(struct pl01x_priv), |
| 93 | }; |