Commit 90efa75f7ab0be5677f0cca155dbf0b39eacdd03
Committed by
Greg Kroah-Hartman
1 parent
e087ab74f3
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
serial: sccnxp: Using CLK API for getting UART clock
This patch removes "frequency" parameter from SCCNXP platform_data and uses CLK API for getting clock. If CLK ommited, default IC frequency will be used instead. Signed-off-by: Alexander Shiyan <shc_work@mail.ru> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 3 changed files with 22 additions and 18 deletions Inline Diff
arch/mips/sni/a20r.c
1 | /* | 1 | /* |
2 | * A20R specific code | 2 | * A20R specific code |
3 | * | 3 | * |
4 | * This file is subject to the terms and conditions of the GNU General Public | 4 | * This file is subject to the terms and conditions of the GNU General Public |
5 | * License. See the file "COPYING" in the main directory of this archive | 5 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 6 | * for more details. |
7 | * | 7 | * |
8 | * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) | 8 | * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/serial_8250.h> | 15 | #include <linux/serial_8250.h> |
16 | 16 | ||
17 | #include <asm/sni.h> | 17 | #include <asm/sni.h> |
18 | #include <asm/time.h> | 18 | #include <asm/time.h> |
19 | 19 | ||
20 | #define PORT(_base,_irq) \ | 20 | #define PORT(_base,_irq) \ |
21 | { \ | 21 | { \ |
22 | .iobase = _base, \ | 22 | .iobase = _base, \ |
23 | .irq = _irq, \ | 23 | .irq = _irq, \ |
24 | .uartclk = 1843200, \ | 24 | .uartclk = 1843200, \ |
25 | .iotype = UPIO_PORT, \ | 25 | .iotype = UPIO_PORT, \ |
26 | .flags = UPF_BOOT_AUTOCONF, \ | 26 | .flags = UPF_BOOT_AUTOCONF, \ |
27 | } | 27 | } |
28 | 28 | ||
29 | static struct plat_serial8250_port a20r_data[] = { | 29 | static struct plat_serial8250_port a20r_data[] = { |
30 | PORT(0x3f8, 4), | 30 | PORT(0x3f8, 4), |
31 | PORT(0x2f8, 3), | 31 | PORT(0x2f8, 3), |
32 | { }, | 32 | { }, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | static struct platform_device a20r_serial8250_device = { | 35 | static struct platform_device a20r_serial8250_device = { |
36 | .name = "serial8250", | 36 | .name = "serial8250", |
37 | .id = PLAT8250_DEV_PLATFORM, | 37 | .id = PLAT8250_DEV_PLATFORM, |
38 | .dev = { | 38 | .dev = { |
39 | .platform_data = a20r_data, | 39 | .platform_data = a20r_data, |
40 | }, | 40 | }, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static struct resource a20r_ds1216_rsrc[] = { | 43 | static struct resource a20r_ds1216_rsrc[] = { |
44 | { | 44 | { |
45 | .start = 0x1c081ffc, | 45 | .start = 0x1c081ffc, |
46 | .end = 0x1c081fff, | 46 | .end = 0x1c081fff, |
47 | .flags = IORESOURCE_MEM | 47 | .flags = IORESOURCE_MEM |
48 | } | 48 | } |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static struct platform_device a20r_ds1216_device = { | 51 | static struct platform_device a20r_ds1216_device = { |
52 | .name = "rtc-ds1216", | 52 | .name = "rtc-ds1216", |
53 | .num_resources = ARRAY_SIZE(a20r_ds1216_rsrc), | 53 | .num_resources = ARRAY_SIZE(a20r_ds1216_rsrc), |
54 | .resource = a20r_ds1216_rsrc | 54 | .resource = a20r_ds1216_rsrc |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static struct resource snirm_82596_rsrc[] = { | 57 | static struct resource snirm_82596_rsrc[] = { |
58 | { | 58 | { |
59 | .start = 0x18000000, | 59 | .start = 0x18000000, |
60 | .end = 0x18000004, | 60 | .end = 0x18000004, |
61 | .flags = IORESOURCE_MEM | 61 | .flags = IORESOURCE_MEM |
62 | }, | 62 | }, |
63 | { | 63 | { |
64 | .start = 0x18010000, | 64 | .start = 0x18010000, |
65 | .end = 0x18010004, | 65 | .end = 0x18010004, |
66 | .flags = IORESOURCE_MEM | 66 | .flags = IORESOURCE_MEM |
67 | }, | 67 | }, |
68 | { | 68 | { |
69 | .start = 0x1ff00000, | 69 | .start = 0x1ff00000, |
70 | .end = 0x1ff00020, | 70 | .end = 0x1ff00020, |
71 | .flags = IORESOURCE_MEM | 71 | .flags = IORESOURCE_MEM |
72 | }, | 72 | }, |
73 | { | 73 | { |
74 | .start = 22, | 74 | .start = 22, |
75 | .end = 22, | 75 | .end = 22, |
76 | .flags = IORESOURCE_IRQ | 76 | .flags = IORESOURCE_IRQ |
77 | }, | 77 | }, |
78 | { | 78 | { |
79 | .flags = 0x01 /* 16bit mpu port access */ | 79 | .flags = 0x01 /* 16bit mpu port access */ |
80 | } | 80 | } |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static struct platform_device snirm_82596_pdev = { | 83 | static struct platform_device snirm_82596_pdev = { |
84 | .name = "snirm_82596", | 84 | .name = "snirm_82596", |
85 | .num_resources = ARRAY_SIZE(snirm_82596_rsrc), | 85 | .num_resources = ARRAY_SIZE(snirm_82596_rsrc), |
86 | .resource = snirm_82596_rsrc | 86 | .resource = snirm_82596_rsrc |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static struct resource snirm_53c710_rsrc[] = { | 89 | static struct resource snirm_53c710_rsrc[] = { |
90 | { | 90 | { |
91 | .start = 0x19000000, | 91 | .start = 0x19000000, |
92 | .end = 0x190fffff, | 92 | .end = 0x190fffff, |
93 | .flags = IORESOURCE_MEM | 93 | .flags = IORESOURCE_MEM |
94 | }, | 94 | }, |
95 | { | 95 | { |
96 | .start = 19, | 96 | .start = 19, |
97 | .end = 19, | 97 | .end = 19, |
98 | .flags = IORESOURCE_IRQ | 98 | .flags = IORESOURCE_IRQ |
99 | } | 99 | } |
100 | }; | 100 | }; |
101 | 101 | ||
102 | static struct platform_device snirm_53c710_pdev = { | 102 | static struct platform_device snirm_53c710_pdev = { |
103 | .name = "snirm_53c710", | 103 | .name = "snirm_53c710", |
104 | .num_resources = ARRAY_SIZE(snirm_53c710_rsrc), | 104 | .num_resources = ARRAY_SIZE(snirm_53c710_rsrc), |
105 | .resource = snirm_53c710_rsrc | 105 | .resource = snirm_53c710_rsrc |
106 | }; | 106 | }; |
107 | 107 | ||
108 | static struct resource sc26xx_rsrc[] = { | 108 | static struct resource sc26xx_rsrc[] = { |
109 | { | 109 | { |
110 | .start = 0x1c070000, | 110 | .start = 0x1c070000, |
111 | .end = 0x1c0700ff, | 111 | .end = 0x1c0700ff, |
112 | .flags = IORESOURCE_MEM | 112 | .flags = IORESOURCE_MEM |
113 | }, | 113 | }, |
114 | { | 114 | { |
115 | .start = 20, | 115 | .start = 20, |
116 | .end = 20, | 116 | .end = 20, |
117 | .flags = IORESOURCE_IRQ | 117 | .flags = IORESOURCE_IRQ |
118 | } | 118 | } |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #include <linux/platform_data/serial-sccnxp.h> | 121 | #include <linux/platform_data/serial-sccnxp.h> |
122 | 122 | ||
123 | static struct sccnxp_pdata sccnxp_data = { | 123 | static struct sccnxp_pdata sccnxp_data = { |
124 | .reg_shift = 2, | 124 | .reg_shift = 2, |
125 | .frequency = 3686400, | ||
126 | .mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) | | 125 | .mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) | |
127 | MCTRL_SIG(RTS_OP, LINE_OP3) | | 126 | MCTRL_SIG(RTS_OP, LINE_OP3) | |
128 | MCTRL_SIG(DSR_IP, LINE_IP5) | | 127 | MCTRL_SIG(DSR_IP, LINE_IP5) | |
129 | MCTRL_SIG(DCD_IP, LINE_IP6), | 128 | MCTRL_SIG(DCD_IP, LINE_IP6), |
130 | .mctrl_cfg[1] = MCTRL_SIG(DTR_OP, LINE_OP2) | | 129 | .mctrl_cfg[1] = MCTRL_SIG(DTR_OP, LINE_OP2) | |
131 | MCTRL_SIG(RTS_OP, LINE_OP1) | | 130 | MCTRL_SIG(RTS_OP, LINE_OP1) | |
132 | MCTRL_SIG(DSR_IP, LINE_IP0) | | 131 | MCTRL_SIG(DSR_IP, LINE_IP0) | |
133 | MCTRL_SIG(CTS_IP, LINE_IP1) | | 132 | MCTRL_SIG(CTS_IP, LINE_IP1) | |
134 | MCTRL_SIG(DCD_IP, LINE_IP2) | | 133 | MCTRL_SIG(DCD_IP, LINE_IP2) | |
135 | MCTRL_SIG(RNG_IP, LINE_IP3), | 134 | MCTRL_SIG(RNG_IP, LINE_IP3), |
136 | }; | 135 | }; |
137 | 136 | ||
138 | static struct platform_device sc26xx_pdev = { | 137 | static struct platform_device sc26xx_pdev = { |
139 | .name = "sc2681", | 138 | .name = "sc2681", |
140 | .resource = sc26xx_rsrc, | 139 | .resource = sc26xx_rsrc, |
141 | .num_resources = ARRAY_SIZE(sc26xx_rsrc), | 140 | .num_resources = ARRAY_SIZE(sc26xx_rsrc), |
142 | .dev = { | 141 | .dev = { |
143 | .platform_data = &sccnxp_data, | 142 | .platform_data = &sccnxp_data, |
144 | }, | 143 | }, |
145 | }; | 144 | }; |
146 | 145 | ||
147 | static u32 a20r_ack_hwint(void) | 146 | static u32 a20r_ack_hwint(void) |
148 | { | 147 | { |
149 | u32 status = read_c0_status(); | 148 | u32 status = read_c0_status(); |
150 | 149 | ||
151 | write_c0_status(status | 0x00010000); | 150 | write_c0_status(status | 0x00010000); |
152 | asm volatile( | 151 | asm volatile( |
153 | " .set push \n" | 152 | " .set push \n" |
154 | " .set noat \n" | 153 | " .set noat \n" |
155 | " .set noreorder \n" | 154 | " .set noreorder \n" |
156 | " lw $1, 0(%0) \n" | 155 | " lw $1, 0(%0) \n" |
157 | " sb $0, 0(%1) \n" | 156 | " sb $0, 0(%1) \n" |
158 | " sync \n" | 157 | " sync \n" |
159 | " lb %1, 0(%1) \n" | 158 | " lb %1, 0(%1) \n" |
160 | " b 1f \n" | 159 | " b 1f \n" |
161 | " ori %1, $1, 2 \n" | 160 | " ori %1, $1, 2 \n" |
162 | " .align 8 \n" | 161 | " .align 8 \n" |
163 | "1: \n" | 162 | "1: \n" |
164 | " nop \n" | 163 | " nop \n" |
165 | " sw %1, 0(%0) \n" | 164 | " sw %1, 0(%0) \n" |
166 | " sync \n" | 165 | " sync \n" |
167 | " li %1, 0x20 \n" | 166 | " li %1, 0x20 \n" |
168 | "2: \n" | 167 | "2: \n" |
169 | " nop \n" | 168 | " nop \n" |
170 | " bnez %1,2b \n" | 169 | " bnez %1,2b \n" |
171 | " addiu %1, -1 \n" | 170 | " addiu %1, -1 \n" |
172 | " sw $1, 0(%0) \n" | 171 | " sw $1, 0(%0) \n" |
173 | " sync \n" | 172 | " sync \n" |
174 | ".set pop \n" | 173 | ".set pop \n" |
175 | : | 174 | : |
176 | : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000)); | 175 | : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000)); |
177 | write_c0_status(status); | 176 | write_c0_status(status); |
178 | 177 | ||
179 | return status; | 178 | return status; |
180 | } | 179 | } |
181 | 180 | ||
182 | static inline void unmask_a20r_irq(struct irq_data *d) | 181 | static inline void unmask_a20r_irq(struct irq_data *d) |
183 | { | 182 | { |
184 | set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); | 183 | set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); |
185 | irq_enable_hazard(); | 184 | irq_enable_hazard(); |
186 | } | 185 | } |
187 | 186 | ||
188 | static inline void mask_a20r_irq(struct irq_data *d) | 187 | static inline void mask_a20r_irq(struct irq_data *d) |
189 | { | 188 | { |
190 | clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); | 189 | clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); |
191 | irq_disable_hazard(); | 190 | irq_disable_hazard(); |
192 | } | 191 | } |
193 | 192 | ||
194 | static struct irq_chip a20r_irq_type = { | 193 | static struct irq_chip a20r_irq_type = { |
195 | .name = "A20R", | 194 | .name = "A20R", |
196 | .irq_mask = mask_a20r_irq, | 195 | .irq_mask = mask_a20r_irq, |
197 | .irq_unmask = unmask_a20r_irq, | 196 | .irq_unmask = unmask_a20r_irq, |
198 | }; | 197 | }; |
199 | 198 | ||
200 | /* | 199 | /* |
201 | * hwint 0 receive all interrupts | 200 | * hwint 0 receive all interrupts |
202 | */ | 201 | */ |
203 | static void a20r_hwint(void) | 202 | static void a20r_hwint(void) |
204 | { | 203 | { |
205 | u32 cause, status; | 204 | u32 cause, status; |
206 | int irq; | 205 | int irq; |
207 | 206 | ||
208 | clear_c0_status(IE_IRQ0); | 207 | clear_c0_status(IE_IRQ0); |
209 | status = a20r_ack_hwint(); | 208 | status = a20r_ack_hwint(); |
210 | cause = read_c0_cause(); | 209 | cause = read_c0_cause(); |
211 | 210 | ||
212 | irq = ffs(((cause & status) >> 8) & 0xf8); | 211 | irq = ffs(((cause & status) >> 8) & 0xf8); |
213 | if (likely(irq > 0)) | 212 | if (likely(irq > 0)) |
214 | do_IRQ(SNI_A20R_IRQ_BASE + irq - 1); | 213 | do_IRQ(SNI_A20R_IRQ_BASE + irq - 1); |
215 | set_c0_status(IE_IRQ0); | 214 | set_c0_status(IE_IRQ0); |
216 | } | 215 | } |
217 | 216 | ||
218 | void __init sni_a20r_irq_init(void) | 217 | void __init sni_a20r_irq_init(void) |
219 | { | 218 | { |
220 | int i; | 219 | int i; |
221 | 220 | ||
222 | for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++) | 221 | for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++) |
223 | irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq); | 222 | irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq); |
224 | sni_hwint = a20r_hwint; | 223 | sni_hwint = a20r_hwint; |
225 | change_c0_status(ST0_IM, IE_IRQ0); | 224 | change_c0_status(ST0_IM, IE_IRQ0); |
226 | setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq); | 225 | setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq); |
227 | } | 226 | } |
228 | 227 | ||
229 | void sni_a20r_init(void) | 228 | void sni_a20r_init(void) |
230 | { | 229 | { |
231 | /* FIXME, remove if not needed */ | 230 | /* FIXME, remove if not needed */ |
232 | } | 231 | } |
233 | 232 | ||
234 | static int __init snirm_a20r_setup_devinit(void) | 233 | static int __init snirm_a20r_setup_devinit(void) |
235 | { | 234 | { |
236 | switch (sni_brd_type) { | 235 | switch (sni_brd_type) { |
237 | case SNI_BRD_TOWER_OASIC: | 236 | case SNI_BRD_TOWER_OASIC: |
238 | case SNI_BRD_MINITOWER: | 237 | case SNI_BRD_MINITOWER: |
239 | platform_device_register(&snirm_82596_pdev); | 238 | platform_device_register(&snirm_82596_pdev); |
240 | platform_device_register(&snirm_53c710_pdev); | 239 | platform_device_register(&snirm_53c710_pdev); |
241 | platform_device_register(&sc26xx_pdev); | 240 | platform_device_register(&sc26xx_pdev); |
242 | platform_device_register(&a20r_serial8250_device); | 241 | platform_device_register(&a20r_serial8250_device); |
243 | platform_device_register(&a20r_ds1216_device); | 242 | platform_device_register(&a20r_ds1216_device); |
244 | sni_eisa_root_init(); | 243 | sni_eisa_root_init(); |
245 | break; | 244 | break; |
246 | } | 245 | } |
247 | return 0; | 246 | return 0; |
248 | } | 247 | } |
249 | 248 | ||
250 | device_initcall(snirm_a20r_setup_devinit); | 249 | device_initcall(snirm_a20r_setup_devinit); |
251 | 250 |
drivers/tty/serial/sccnxp.c
1 | /* | 1 | /* |
2 | * NXP (Philips) SCC+++(SCN+++) serial driver | 2 | * NXP (Philips) SCC+++(SCN+++) serial driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | 4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> |
5 | * | 5 | * |
6 | * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) | 6 | * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 14 | #if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
15 | #define SUPPORT_SYSRQ | 15 | #define SUPPORT_SYSRQ |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | #include <linux/clk.h> | ||
18 | #include <linux/err.h> | 19 | #include <linux/err.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/device.h> | 21 | #include <linux/device.h> |
21 | #include <linux/console.h> | 22 | #include <linux/console.h> |
22 | #include <linux/serial_core.h> | 23 | #include <linux/serial_core.h> |
23 | #include <linux/serial.h> | 24 | #include <linux/serial.h> |
24 | #include <linux/io.h> | 25 | #include <linux/io.h> |
25 | #include <linux/tty.h> | 26 | #include <linux/tty.h> |
26 | #include <linux/tty_flip.h> | 27 | #include <linux/tty_flip.h> |
27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
29 | #include <linux/platform_data/serial-sccnxp.h> | 30 | #include <linux/platform_data/serial-sccnxp.h> |
30 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
31 | 32 | ||
32 | #define SCCNXP_NAME "uart-sccnxp" | 33 | #define SCCNXP_NAME "uart-sccnxp" |
33 | #define SCCNXP_MAJOR 204 | 34 | #define SCCNXP_MAJOR 204 |
34 | #define SCCNXP_MINOR 205 | 35 | #define SCCNXP_MINOR 205 |
35 | 36 | ||
36 | #define SCCNXP_MR_REG (0x00) | 37 | #define SCCNXP_MR_REG (0x00) |
37 | # define MR0_BAUD_NORMAL (0 << 0) | 38 | # define MR0_BAUD_NORMAL (0 << 0) |
38 | # define MR0_BAUD_EXT1 (1 << 0) | 39 | # define MR0_BAUD_EXT1 (1 << 0) |
39 | # define MR0_BAUD_EXT2 (5 << 0) | 40 | # define MR0_BAUD_EXT2 (5 << 0) |
40 | # define MR0_FIFO (1 << 3) | 41 | # define MR0_FIFO (1 << 3) |
41 | # define MR0_TXLVL (1 << 4) | 42 | # define MR0_TXLVL (1 << 4) |
42 | # define MR1_BITS_5 (0 << 0) | 43 | # define MR1_BITS_5 (0 << 0) |
43 | # define MR1_BITS_6 (1 << 0) | 44 | # define MR1_BITS_6 (1 << 0) |
44 | # define MR1_BITS_7 (2 << 0) | 45 | # define MR1_BITS_7 (2 << 0) |
45 | # define MR1_BITS_8 (3 << 0) | 46 | # define MR1_BITS_8 (3 << 0) |
46 | # define MR1_PAR_EVN (0 << 2) | 47 | # define MR1_PAR_EVN (0 << 2) |
47 | # define MR1_PAR_ODD (1 << 2) | 48 | # define MR1_PAR_ODD (1 << 2) |
48 | # define MR1_PAR_NO (4 << 2) | 49 | # define MR1_PAR_NO (4 << 2) |
49 | # define MR2_STOP1 (7 << 0) | 50 | # define MR2_STOP1 (7 << 0) |
50 | # define MR2_STOP2 (0xf << 0) | 51 | # define MR2_STOP2 (0xf << 0) |
51 | #define SCCNXP_SR_REG (0x01) | 52 | #define SCCNXP_SR_REG (0x01) |
52 | #define SCCNXP_CSR_REG SCCNXP_SR_REG | 53 | #define SCCNXP_CSR_REG SCCNXP_SR_REG |
53 | # define SR_RXRDY (1 << 0) | 54 | # define SR_RXRDY (1 << 0) |
54 | # define SR_FULL (1 << 1) | 55 | # define SR_FULL (1 << 1) |
55 | # define SR_TXRDY (1 << 2) | 56 | # define SR_TXRDY (1 << 2) |
56 | # define SR_TXEMT (1 << 3) | 57 | # define SR_TXEMT (1 << 3) |
57 | # define SR_OVR (1 << 4) | 58 | # define SR_OVR (1 << 4) |
58 | # define SR_PE (1 << 5) | 59 | # define SR_PE (1 << 5) |
59 | # define SR_FE (1 << 6) | 60 | # define SR_FE (1 << 6) |
60 | # define SR_BRK (1 << 7) | 61 | # define SR_BRK (1 << 7) |
61 | #define SCCNXP_CR_REG (0x02) | 62 | #define SCCNXP_CR_REG (0x02) |
62 | # define CR_RX_ENABLE (1 << 0) | 63 | # define CR_RX_ENABLE (1 << 0) |
63 | # define CR_RX_DISABLE (1 << 1) | 64 | # define CR_RX_DISABLE (1 << 1) |
64 | # define CR_TX_ENABLE (1 << 2) | 65 | # define CR_TX_ENABLE (1 << 2) |
65 | # define CR_TX_DISABLE (1 << 3) | 66 | # define CR_TX_DISABLE (1 << 3) |
66 | # define CR_CMD_MRPTR1 (0x01 << 4) | 67 | # define CR_CMD_MRPTR1 (0x01 << 4) |
67 | # define CR_CMD_RX_RESET (0x02 << 4) | 68 | # define CR_CMD_RX_RESET (0x02 << 4) |
68 | # define CR_CMD_TX_RESET (0x03 << 4) | 69 | # define CR_CMD_TX_RESET (0x03 << 4) |
69 | # define CR_CMD_STATUS_RESET (0x04 << 4) | 70 | # define CR_CMD_STATUS_RESET (0x04 << 4) |
70 | # define CR_CMD_BREAK_RESET (0x05 << 4) | 71 | # define CR_CMD_BREAK_RESET (0x05 << 4) |
71 | # define CR_CMD_START_BREAK (0x06 << 4) | 72 | # define CR_CMD_START_BREAK (0x06 << 4) |
72 | # define CR_CMD_STOP_BREAK (0x07 << 4) | 73 | # define CR_CMD_STOP_BREAK (0x07 << 4) |
73 | # define CR_CMD_MRPTR0 (0x0b << 4) | 74 | # define CR_CMD_MRPTR0 (0x0b << 4) |
74 | #define SCCNXP_RHR_REG (0x03) | 75 | #define SCCNXP_RHR_REG (0x03) |
75 | #define SCCNXP_THR_REG SCCNXP_RHR_REG | 76 | #define SCCNXP_THR_REG SCCNXP_RHR_REG |
76 | #define SCCNXP_IPCR_REG (0x04) | 77 | #define SCCNXP_IPCR_REG (0x04) |
77 | #define SCCNXP_ACR_REG SCCNXP_IPCR_REG | 78 | #define SCCNXP_ACR_REG SCCNXP_IPCR_REG |
78 | # define ACR_BAUD0 (0 << 7) | 79 | # define ACR_BAUD0 (0 << 7) |
79 | # define ACR_BAUD1 (1 << 7) | 80 | # define ACR_BAUD1 (1 << 7) |
80 | # define ACR_TIMER_MODE (6 << 4) | 81 | # define ACR_TIMER_MODE (6 << 4) |
81 | #define SCCNXP_ISR_REG (0x05) | 82 | #define SCCNXP_ISR_REG (0x05) |
82 | #define SCCNXP_IMR_REG SCCNXP_ISR_REG | 83 | #define SCCNXP_IMR_REG SCCNXP_ISR_REG |
83 | # define IMR_TXRDY (1 << 0) | 84 | # define IMR_TXRDY (1 << 0) |
84 | # define IMR_RXRDY (1 << 1) | 85 | # define IMR_RXRDY (1 << 1) |
85 | # define ISR_TXRDY(x) (1 << ((x * 4) + 0)) | 86 | # define ISR_TXRDY(x) (1 << ((x * 4) + 0)) |
86 | # define ISR_RXRDY(x) (1 << ((x * 4) + 1)) | 87 | # define ISR_RXRDY(x) (1 << ((x * 4) + 1)) |
87 | #define SCCNXP_IPR_REG (0x0d) | 88 | #define SCCNXP_IPR_REG (0x0d) |
88 | #define SCCNXP_OPCR_REG SCCNXP_IPR_REG | 89 | #define SCCNXP_OPCR_REG SCCNXP_IPR_REG |
89 | #define SCCNXP_SOP_REG (0x0e) | 90 | #define SCCNXP_SOP_REG (0x0e) |
90 | #define SCCNXP_ROP_REG (0x0f) | 91 | #define SCCNXP_ROP_REG (0x0f) |
91 | 92 | ||
92 | /* Route helpers */ | 93 | /* Route helpers */ |
93 | #define MCTRL_MASK(sig) (0xf << (sig)) | 94 | #define MCTRL_MASK(sig) (0xf << (sig)) |
94 | #define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0) | 95 | #define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0) |
95 | #define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0) | 96 | #define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0) |
96 | 97 | ||
97 | /* Supported chip types */ | 98 | /* Supported chip types */ |
98 | enum { | 99 | enum { |
99 | SCCNXP_TYPE_SC2681 = 2681, | 100 | SCCNXP_TYPE_SC2681 = 2681, |
100 | SCCNXP_TYPE_SC2691 = 2691, | 101 | SCCNXP_TYPE_SC2691 = 2691, |
101 | SCCNXP_TYPE_SC2692 = 2692, | 102 | SCCNXP_TYPE_SC2692 = 2692, |
102 | SCCNXP_TYPE_SC2891 = 2891, | 103 | SCCNXP_TYPE_SC2891 = 2891, |
103 | SCCNXP_TYPE_SC2892 = 2892, | 104 | SCCNXP_TYPE_SC2892 = 2892, |
104 | SCCNXP_TYPE_SC28202 = 28202, | 105 | SCCNXP_TYPE_SC28202 = 28202, |
105 | SCCNXP_TYPE_SC68681 = 68681, | 106 | SCCNXP_TYPE_SC68681 = 68681, |
106 | SCCNXP_TYPE_SC68692 = 68692, | 107 | SCCNXP_TYPE_SC68692 = 68692, |
107 | }; | 108 | }; |
108 | 109 | ||
109 | struct sccnxp_port { | 110 | struct sccnxp_port { |
110 | struct uart_driver uart; | 111 | struct uart_driver uart; |
111 | struct uart_port port[SCCNXP_MAX_UARTS]; | 112 | struct uart_port port[SCCNXP_MAX_UARTS]; |
112 | bool opened[SCCNXP_MAX_UARTS]; | 113 | bool opened[SCCNXP_MAX_UARTS]; |
113 | 114 | ||
114 | const char *name; | 115 | const char *name; |
115 | int irq; | 116 | int irq; |
116 | 117 | ||
117 | u8 imr; | 118 | u8 imr; |
118 | u8 addr_mask; | 119 | u8 addr_mask; |
119 | int freq_std; | 120 | int freq_std; |
120 | 121 | ||
121 | int flags; | 122 | int flags; |
122 | #define SCCNXP_HAVE_IO 0x00000001 | 123 | #define SCCNXP_HAVE_IO 0x00000001 |
123 | #define SCCNXP_HAVE_MR0 0x00000002 | 124 | #define SCCNXP_HAVE_MR0 0x00000002 |
124 | 125 | ||
125 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE | 126 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE |
126 | struct console console; | 127 | struct console console; |
127 | #endif | 128 | #endif |
128 | 129 | ||
129 | spinlock_t lock; | 130 | spinlock_t lock; |
130 | 131 | ||
131 | bool poll; | 132 | bool poll; |
132 | struct timer_list timer; | 133 | struct timer_list timer; |
133 | 134 | ||
134 | struct sccnxp_pdata pdata; | 135 | struct sccnxp_pdata pdata; |
135 | 136 | ||
136 | struct regulator *regulator; | 137 | struct regulator *regulator; |
137 | }; | 138 | }; |
138 | 139 | ||
139 | static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) | 140 | static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) |
140 | { | 141 | { |
141 | return readb(base + (reg << shift)); | 142 | return readb(base + (reg << shift)); |
142 | } | 143 | } |
143 | 144 | ||
144 | static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v) | 145 | static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v) |
145 | { | 146 | { |
146 | writeb(v, base + (reg << shift)); | 147 | writeb(v, base + (reg << shift)); |
147 | } | 148 | } |
148 | 149 | ||
149 | static inline u8 sccnxp_read(struct uart_port *port, u8 reg) | 150 | static inline u8 sccnxp_read(struct uart_port *port, u8 reg) |
150 | { | 151 | { |
151 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 152 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
152 | 153 | ||
153 | return sccnxp_raw_read(port->membase, reg & s->addr_mask, | 154 | return sccnxp_raw_read(port->membase, reg & s->addr_mask, |
154 | port->regshift); | 155 | port->regshift); |
155 | } | 156 | } |
156 | 157 | ||
157 | static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) | 158 | static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) |
158 | { | 159 | { |
159 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 160 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
160 | 161 | ||
161 | sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v); | 162 | sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v); |
162 | } | 163 | } |
163 | 164 | ||
164 | static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) | 165 | static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) |
165 | { | 166 | { |
166 | return sccnxp_read(port, (port->line << 3) + reg); | 167 | return sccnxp_read(port, (port->line << 3) + reg); |
167 | } | 168 | } |
168 | 169 | ||
169 | static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) | 170 | static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) |
170 | { | 171 | { |
171 | sccnxp_write(port, (port->line << 3) + reg, v); | 172 | sccnxp_write(port, (port->line << 3) + reg, v); |
172 | } | 173 | } |
173 | 174 | ||
174 | static int sccnxp_update_best_err(int a, int b, int *besterr) | 175 | static int sccnxp_update_best_err(int a, int b, int *besterr) |
175 | { | 176 | { |
176 | int err = abs(a - b); | 177 | int err = abs(a - b); |
177 | 178 | ||
178 | if ((*besterr < 0) || (*besterr > err)) { | 179 | if ((*besterr < 0) || (*besterr > err)) { |
179 | *besterr = err; | 180 | *besterr = err; |
180 | return 0; | 181 | return 0; |
181 | } | 182 | } |
182 | 183 | ||
183 | return 1; | 184 | return 1; |
184 | } | 185 | } |
185 | 186 | ||
186 | static const struct { | 187 | static const struct { |
187 | u8 csr; | 188 | u8 csr; |
188 | u8 acr; | 189 | u8 acr; |
189 | u8 mr0; | 190 | u8 mr0; |
190 | int baud; | 191 | int baud; |
191 | } baud_std[] = { | 192 | } baud_std[] = { |
192 | { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, | 193 | { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, |
193 | { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, | 194 | { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, |
194 | { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, | 195 | { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, |
195 | { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, }, | 196 | { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, }, |
196 | { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, }, | 197 | { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, }, |
197 | { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, }, | 198 | { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, }, |
198 | { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, }, | 199 | { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, }, |
199 | { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, }, | 200 | { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, }, |
200 | { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, }, | 201 | { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, }, |
201 | { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, }, | 202 | { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, }, |
202 | { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, }, | 203 | { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, }, |
203 | { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, }, | 204 | { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, }, |
204 | { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, }, | 205 | { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, }, |
205 | { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, }, | 206 | { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, }, |
206 | { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, }, | 207 | { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, }, |
207 | { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, }, | 208 | { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, }, |
208 | { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, }, | 209 | { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, }, |
209 | { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, }, | 210 | { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, }, |
210 | { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, }, | 211 | { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, }, |
211 | { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, }, | 212 | { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, }, |
212 | { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, }, | 213 | { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, }, |
213 | { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, }, | 214 | { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, }, |
214 | { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, }, | 215 | { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, }, |
215 | { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, }, | 216 | { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, }, |
216 | { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, }, | 217 | { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, }, |
217 | { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, }, | 218 | { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, }, |
218 | { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, }, | 219 | { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, }, |
219 | { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, }, | 220 | { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, }, |
220 | { 0, 0, 0, 0 } | 221 | { 0, 0, 0, 0 } |
221 | }; | 222 | }; |
222 | 223 | ||
223 | static int sccnxp_set_baud(struct uart_port *port, int baud) | 224 | static int sccnxp_set_baud(struct uart_port *port, int baud) |
224 | { | 225 | { |
225 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 226 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
226 | int div_std, tmp_baud, bestbaud = baud, besterr = -1; | 227 | int div_std, tmp_baud, bestbaud = baud, besterr = -1; |
227 | u8 i, acr = 0, csr = 0, mr0 = 0; | 228 | u8 i, acr = 0, csr = 0, mr0 = 0; |
228 | 229 | ||
229 | /* Find best baud from table */ | 230 | /* Find best baud from table */ |
230 | for (i = 0; baud_std[i].baud && besterr; i++) { | 231 | for (i = 0; baud_std[i].baud && besterr; i++) { |
231 | if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0)) | 232 | if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0)) |
232 | continue; | 233 | continue; |
233 | div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud); | 234 | div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud); |
234 | tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std); | 235 | tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std); |
235 | if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) { | 236 | if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) { |
236 | acr = baud_std[i].acr; | 237 | acr = baud_std[i].acr; |
237 | csr = baud_std[i].csr; | 238 | csr = baud_std[i].csr; |
238 | mr0 = baud_std[i].mr0; | 239 | mr0 = baud_std[i].mr0; |
239 | bestbaud = tmp_baud; | 240 | bestbaud = tmp_baud; |
240 | } | 241 | } |
241 | } | 242 | } |
242 | 243 | ||
243 | if (s->flags & SCCNXP_HAVE_MR0) { | 244 | if (s->flags & SCCNXP_HAVE_MR0) { |
244 | /* Enable FIFO, set half level for TX */ | 245 | /* Enable FIFO, set half level for TX */ |
245 | mr0 |= MR0_FIFO | MR0_TXLVL; | 246 | mr0 |= MR0_FIFO | MR0_TXLVL; |
246 | /* Update MR0 */ | 247 | /* Update MR0 */ |
247 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0); | 248 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0); |
248 | sccnxp_port_write(port, SCCNXP_MR_REG, mr0); | 249 | sccnxp_port_write(port, SCCNXP_MR_REG, mr0); |
249 | } | 250 | } |
250 | 251 | ||
251 | sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE); | 252 | sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE); |
252 | sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr); | 253 | sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr); |
253 | 254 | ||
254 | if (baud != bestbaud) | 255 | if (baud != bestbaud) |
255 | dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n", | 256 | dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n", |
256 | baud, bestbaud); | 257 | baud, bestbaud); |
257 | 258 | ||
258 | return bestbaud; | 259 | return bestbaud; |
259 | } | 260 | } |
260 | 261 | ||
261 | static void sccnxp_enable_irq(struct uart_port *port, int mask) | 262 | static void sccnxp_enable_irq(struct uart_port *port, int mask) |
262 | { | 263 | { |
263 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 264 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
264 | 265 | ||
265 | s->imr |= mask << (port->line * 4); | 266 | s->imr |= mask << (port->line * 4); |
266 | sccnxp_write(port, SCCNXP_IMR_REG, s->imr); | 267 | sccnxp_write(port, SCCNXP_IMR_REG, s->imr); |
267 | } | 268 | } |
268 | 269 | ||
269 | static void sccnxp_disable_irq(struct uart_port *port, int mask) | 270 | static void sccnxp_disable_irq(struct uart_port *port, int mask) |
270 | { | 271 | { |
271 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 272 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
272 | 273 | ||
273 | s->imr &= ~(mask << (port->line * 4)); | 274 | s->imr &= ~(mask << (port->line * 4)); |
274 | sccnxp_write(port, SCCNXP_IMR_REG, s->imr); | 275 | sccnxp_write(port, SCCNXP_IMR_REG, s->imr); |
275 | } | 276 | } |
276 | 277 | ||
277 | static void sccnxp_set_bit(struct uart_port *port, int sig, int state) | 278 | static void sccnxp_set_bit(struct uart_port *port, int sig, int state) |
278 | { | 279 | { |
279 | u8 bitmask; | 280 | u8 bitmask; |
280 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 281 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
281 | 282 | ||
282 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) { | 283 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) { |
283 | bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig); | 284 | bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig); |
284 | if (state) | 285 | if (state) |
285 | sccnxp_write(port, SCCNXP_SOP_REG, bitmask); | 286 | sccnxp_write(port, SCCNXP_SOP_REG, bitmask); |
286 | else | 287 | else |
287 | sccnxp_write(port, SCCNXP_ROP_REG, bitmask); | 288 | sccnxp_write(port, SCCNXP_ROP_REG, bitmask); |
288 | } | 289 | } |
289 | } | 290 | } |
290 | 291 | ||
291 | static void sccnxp_handle_rx(struct uart_port *port) | 292 | static void sccnxp_handle_rx(struct uart_port *port) |
292 | { | 293 | { |
293 | u8 sr; | 294 | u8 sr; |
294 | unsigned int ch, flag; | 295 | unsigned int ch, flag; |
295 | 296 | ||
296 | for (;;) { | 297 | for (;;) { |
297 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); | 298 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); |
298 | if (!(sr & SR_RXRDY)) | 299 | if (!(sr & SR_RXRDY)) |
299 | break; | 300 | break; |
300 | sr &= SR_PE | SR_FE | SR_OVR | SR_BRK; | 301 | sr &= SR_PE | SR_FE | SR_OVR | SR_BRK; |
301 | 302 | ||
302 | ch = sccnxp_port_read(port, SCCNXP_RHR_REG); | 303 | ch = sccnxp_port_read(port, SCCNXP_RHR_REG); |
303 | 304 | ||
304 | port->icount.rx++; | 305 | port->icount.rx++; |
305 | flag = TTY_NORMAL; | 306 | flag = TTY_NORMAL; |
306 | 307 | ||
307 | if (unlikely(sr)) { | 308 | if (unlikely(sr)) { |
308 | if (sr & SR_BRK) { | 309 | if (sr & SR_BRK) { |
309 | port->icount.brk++; | 310 | port->icount.brk++; |
310 | sccnxp_port_write(port, SCCNXP_CR_REG, | 311 | sccnxp_port_write(port, SCCNXP_CR_REG, |
311 | CR_CMD_BREAK_RESET); | 312 | CR_CMD_BREAK_RESET); |
312 | if (uart_handle_break(port)) | 313 | if (uart_handle_break(port)) |
313 | continue; | 314 | continue; |
314 | } else if (sr & SR_PE) | 315 | } else if (sr & SR_PE) |
315 | port->icount.parity++; | 316 | port->icount.parity++; |
316 | else if (sr & SR_FE) | 317 | else if (sr & SR_FE) |
317 | port->icount.frame++; | 318 | port->icount.frame++; |
318 | else if (sr & SR_OVR) { | 319 | else if (sr & SR_OVR) { |
319 | port->icount.overrun++; | 320 | port->icount.overrun++; |
320 | sccnxp_port_write(port, SCCNXP_CR_REG, | 321 | sccnxp_port_write(port, SCCNXP_CR_REG, |
321 | CR_CMD_STATUS_RESET); | 322 | CR_CMD_STATUS_RESET); |
322 | } | 323 | } |
323 | 324 | ||
324 | sr &= port->read_status_mask; | 325 | sr &= port->read_status_mask; |
325 | if (sr & SR_BRK) | 326 | if (sr & SR_BRK) |
326 | flag = TTY_BREAK; | 327 | flag = TTY_BREAK; |
327 | else if (sr & SR_PE) | 328 | else if (sr & SR_PE) |
328 | flag = TTY_PARITY; | 329 | flag = TTY_PARITY; |
329 | else if (sr & SR_FE) | 330 | else if (sr & SR_FE) |
330 | flag = TTY_FRAME; | 331 | flag = TTY_FRAME; |
331 | else if (sr & SR_OVR) | 332 | else if (sr & SR_OVR) |
332 | flag = TTY_OVERRUN; | 333 | flag = TTY_OVERRUN; |
333 | } | 334 | } |
334 | 335 | ||
335 | if (uart_handle_sysrq_char(port, ch)) | 336 | if (uart_handle_sysrq_char(port, ch)) |
336 | continue; | 337 | continue; |
337 | 338 | ||
338 | if (sr & port->ignore_status_mask) | 339 | if (sr & port->ignore_status_mask) |
339 | continue; | 340 | continue; |
340 | 341 | ||
341 | uart_insert_char(port, sr, SR_OVR, ch, flag); | 342 | uart_insert_char(port, sr, SR_OVR, ch, flag); |
342 | } | 343 | } |
343 | 344 | ||
344 | tty_flip_buffer_push(&port->state->port); | 345 | tty_flip_buffer_push(&port->state->port); |
345 | } | 346 | } |
346 | 347 | ||
347 | static void sccnxp_handle_tx(struct uart_port *port) | 348 | static void sccnxp_handle_tx(struct uart_port *port) |
348 | { | 349 | { |
349 | u8 sr; | 350 | u8 sr; |
350 | struct circ_buf *xmit = &port->state->xmit; | 351 | struct circ_buf *xmit = &port->state->xmit; |
351 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 352 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
352 | 353 | ||
353 | if (unlikely(port->x_char)) { | 354 | if (unlikely(port->x_char)) { |
354 | sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char); | 355 | sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char); |
355 | port->icount.tx++; | 356 | port->icount.tx++; |
356 | port->x_char = 0; | 357 | port->x_char = 0; |
357 | return; | 358 | return; |
358 | } | 359 | } |
359 | 360 | ||
360 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | 361 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { |
361 | /* Disable TX if FIFO is empty */ | 362 | /* Disable TX if FIFO is empty */ |
362 | if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { | 363 | if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { |
363 | sccnxp_disable_irq(port, IMR_TXRDY); | 364 | sccnxp_disable_irq(port, IMR_TXRDY); |
364 | 365 | ||
365 | /* Set direction to input */ | 366 | /* Set direction to input */ |
366 | if (s->flags & SCCNXP_HAVE_IO) | 367 | if (s->flags & SCCNXP_HAVE_IO) |
367 | sccnxp_set_bit(port, DIR_OP, 0); | 368 | sccnxp_set_bit(port, DIR_OP, 0); |
368 | } | 369 | } |
369 | return; | 370 | return; |
370 | } | 371 | } |
371 | 372 | ||
372 | while (!uart_circ_empty(xmit)) { | 373 | while (!uart_circ_empty(xmit)) { |
373 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); | 374 | sr = sccnxp_port_read(port, SCCNXP_SR_REG); |
374 | if (!(sr & SR_TXRDY)) | 375 | if (!(sr & SR_TXRDY)) |
375 | break; | 376 | break; |
376 | 377 | ||
377 | sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); | 378 | sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); |
378 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 379 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
379 | port->icount.tx++; | 380 | port->icount.tx++; |
380 | } | 381 | } |
381 | 382 | ||
382 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 383 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
383 | uart_write_wakeup(port); | 384 | uart_write_wakeup(port); |
384 | } | 385 | } |
385 | 386 | ||
386 | static void sccnxp_handle_events(struct sccnxp_port *s) | 387 | static void sccnxp_handle_events(struct sccnxp_port *s) |
387 | { | 388 | { |
388 | int i; | 389 | int i; |
389 | u8 isr; | 390 | u8 isr; |
390 | 391 | ||
391 | do { | 392 | do { |
392 | isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); | 393 | isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); |
393 | isr &= s->imr; | 394 | isr &= s->imr; |
394 | if (!isr) | 395 | if (!isr) |
395 | break; | 396 | break; |
396 | 397 | ||
397 | for (i = 0; i < s->uart.nr; i++) { | 398 | for (i = 0; i < s->uart.nr; i++) { |
398 | if (s->opened[i] && (isr & ISR_RXRDY(i))) | 399 | if (s->opened[i] && (isr & ISR_RXRDY(i))) |
399 | sccnxp_handle_rx(&s->port[i]); | 400 | sccnxp_handle_rx(&s->port[i]); |
400 | if (s->opened[i] && (isr & ISR_TXRDY(i))) | 401 | if (s->opened[i] && (isr & ISR_TXRDY(i))) |
401 | sccnxp_handle_tx(&s->port[i]); | 402 | sccnxp_handle_tx(&s->port[i]); |
402 | } | 403 | } |
403 | } while (1); | 404 | } while (1); |
404 | } | 405 | } |
405 | 406 | ||
406 | static void sccnxp_timer(unsigned long data) | 407 | static void sccnxp_timer(unsigned long data) |
407 | { | 408 | { |
408 | struct sccnxp_port *s = (struct sccnxp_port *)data; | 409 | struct sccnxp_port *s = (struct sccnxp_port *)data; |
409 | unsigned long flags; | 410 | unsigned long flags; |
410 | 411 | ||
411 | spin_lock_irqsave(&s->lock, flags); | 412 | spin_lock_irqsave(&s->lock, flags); |
412 | sccnxp_handle_events(s); | 413 | sccnxp_handle_events(s); |
413 | spin_unlock_irqrestore(&s->lock, flags); | 414 | spin_unlock_irqrestore(&s->lock, flags); |
414 | 415 | ||
415 | if (!timer_pending(&s->timer)) | 416 | if (!timer_pending(&s->timer)) |
416 | mod_timer(&s->timer, jiffies + | 417 | mod_timer(&s->timer, jiffies + |
417 | usecs_to_jiffies(s->pdata.poll_time_us)); | 418 | usecs_to_jiffies(s->pdata.poll_time_us)); |
418 | } | 419 | } |
419 | 420 | ||
420 | static irqreturn_t sccnxp_ist(int irq, void *dev_id) | 421 | static irqreturn_t sccnxp_ist(int irq, void *dev_id) |
421 | { | 422 | { |
422 | struct sccnxp_port *s = (struct sccnxp_port *)dev_id; | 423 | struct sccnxp_port *s = (struct sccnxp_port *)dev_id; |
423 | unsigned long flags; | 424 | unsigned long flags; |
424 | 425 | ||
425 | spin_lock_irqsave(&s->lock, flags); | 426 | spin_lock_irqsave(&s->lock, flags); |
426 | sccnxp_handle_events(s); | 427 | sccnxp_handle_events(s); |
427 | spin_unlock_irqrestore(&s->lock, flags); | 428 | spin_unlock_irqrestore(&s->lock, flags); |
428 | 429 | ||
429 | return IRQ_HANDLED; | 430 | return IRQ_HANDLED; |
430 | } | 431 | } |
431 | 432 | ||
432 | static void sccnxp_start_tx(struct uart_port *port) | 433 | static void sccnxp_start_tx(struct uart_port *port) |
433 | { | 434 | { |
434 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 435 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
435 | unsigned long flags; | 436 | unsigned long flags; |
436 | 437 | ||
437 | spin_lock_irqsave(&s->lock, flags); | 438 | spin_lock_irqsave(&s->lock, flags); |
438 | 439 | ||
439 | /* Set direction to output */ | 440 | /* Set direction to output */ |
440 | if (s->flags & SCCNXP_HAVE_IO) | 441 | if (s->flags & SCCNXP_HAVE_IO) |
441 | sccnxp_set_bit(port, DIR_OP, 1); | 442 | sccnxp_set_bit(port, DIR_OP, 1); |
442 | 443 | ||
443 | sccnxp_enable_irq(port, IMR_TXRDY); | 444 | sccnxp_enable_irq(port, IMR_TXRDY); |
444 | 445 | ||
445 | spin_unlock_irqrestore(&s->lock, flags); | 446 | spin_unlock_irqrestore(&s->lock, flags); |
446 | } | 447 | } |
447 | 448 | ||
448 | static void sccnxp_stop_tx(struct uart_port *port) | 449 | static void sccnxp_stop_tx(struct uart_port *port) |
449 | { | 450 | { |
450 | /* Do nothing */ | 451 | /* Do nothing */ |
451 | } | 452 | } |
452 | 453 | ||
453 | static void sccnxp_stop_rx(struct uart_port *port) | 454 | static void sccnxp_stop_rx(struct uart_port *port) |
454 | { | 455 | { |
455 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 456 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
456 | unsigned long flags; | 457 | unsigned long flags; |
457 | 458 | ||
458 | spin_lock_irqsave(&s->lock, flags); | 459 | spin_lock_irqsave(&s->lock, flags); |
459 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); | 460 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); |
460 | spin_unlock_irqrestore(&s->lock, flags); | 461 | spin_unlock_irqrestore(&s->lock, flags); |
461 | } | 462 | } |
462 | 463 | ||
463 | static unsigned int sccnxp_tx_empty(struct uart_port *port) | 464 | static unsigned int sccnxp_tx_empty(struct uart_port *port) |
464 | { | 465 | { |
465 | u8 val; | 466 | u8 val; |
466 | unsigned long flags; | 467 | unsigned long flags; |
467 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 468 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
468 | 469 | ||
469 | spin_lock_irqsave(&s->lock, flags); | 470 | spin_lock_irqsave(&s->lock, flags); |
470 | val = sccnxp_port_read(port, SCCNXP_SR_REG); | 471 | val = sccnxp_port_read(port, SCCNXP_SR_REG); |
471 | spin_unlock_irqrestore(&s->lock, flags); | 472 | spin_unlock_irqrestore(&s->lock, flags); |
472 | 473 | ||
473 | return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; | 474 | return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; |
474 | } | 475 | } |
475 | 476 | ||
476 | static void sccnxp_enable_ms(struct uart_port *port) | 477 | static void sccnxp_enable_ms(struct uart_port *port) |
477 | { | 478 | { |
478 | /* Do nothing */ | 479 | /* Do nothing */ |
479 | } | 480 | } |
480 | 481 | ||
481 | static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) | 482 | static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) |
482 | { | 483 | { |
483 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 484 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
484 | unsigned long flags; | 485 | unsigned long flags; |
485 | 486 | ||
486 | if (!(s->flags & SCCNXP_HAVE_IO)) | 487 | if (!(s->flags & SCCNXP_HAVE_IO)) |
487 | return; | 488 | return; |
488 | 489 | ||
489 | spin_lock_irqsave(&s->lock, flags); | 490 | spin_lock_irqsave(&s->lock, flags); |
490 | 491 | ||
491 | sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); | 492 | sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); |
492 | sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); | 493 | sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); |
493 | 494 | ||
494 | spin_unlock_irqrestore(&s->lock, flags); | 495 | spin_unlock_irqrestore(&s->lock, flags); |
495 | } | 496 | } |
496 | 497 | ||
497 | static unsigned int sccnxp_get_mctrl(struct uart_port *port) | 498 | static unsigned int sccnxp_get_mctrl(struct uart_port *port) |
498 | { | 499 | { |
499 | u8 bitmask, ipr; | 500 | u8 bitmask, ipr; |
500 | unsigned long flags; | 501 | unsigned long flags; |
501 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 502 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
502 | unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; | 503 | unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; |
503 | 504 | ||
504 | if (!(s->flags & SCCNXP_HAVE_IO)) | 505 | if (!(s->flags & SCCNXP_HAVE_IO)) |
505 | return mctrl; | 506 | return mctrl; |
506 | 507 | ||
507 | spin_lock_irqsave(&s->lock, flags); | 508 | spin_lock_irqsave(&s->lock, flags); |
508 | 509 | ||
509 | ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); | 510 | ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); |
510 | 511 | ||
511 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) { | 512 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) { |
512 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], | 513 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], |
513 | DSR_IP); | 514 | DSR_IP); |
514 | mctrl &= ~TIOCM_DSR; | 515 | mctrl &= ~TIOCM_DSR; |
515 | mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0; | 516 | mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0; |
516 | } | 517 | } |
517 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) { | 518 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) { |
518 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], | 519 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], |
519 | CTS_IP); | 520 | CTS_IP); |
520 | mctrl &= ~TIOCM_CTS; | 521 | mctrl &= ~TIOCM_CTS; |
521 | mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0; | 522 | mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0; |
522 | } | 523 | } |
523 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) { | 524 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) { |
524 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], | 525 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], |
525 | DCD_IP); | 526 | DCD_IP); |
526 | mctrl &= ~TIOCM_CAR; | 527 | mctrl &= ~TIOCM_CAR; |
527 | mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0; | 528 | mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0; |
528 | } | 529 | } |
529 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) { | 530 | if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) { |
530 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], | 531 | bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], |
531 | RNG_IP); | 532 | RNG_IP); |
532 | mctrl &= ~TIOCM_RNG; | 533 | mctrl &= ~TIOCM_RNG; |
533 | mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; | 534 | mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; |
534 | } | 535 | } |
535 | 536 | ||
536 | spin_unlock_irqrestore(&s->lock, flags); | 537 | spin_unlock_irqrestore(&s->lock, flags); |
537 | 538 | ||
538 | return mctrl; | 539 | return mctrl; |
539 | } | 540 | } |
540 | 541 | ||
541 | static void sccnxp_break_ctl(struct uart_port *port, int break_state) | 542 | static void sccnxp_break_ctl(struct uart_port *port, int break_state) |
542 | { | 543 | { |
543 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 544 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
544 | unsigned long flags; | 545 | unsigned long flags; |
545 | 546 | ||
546 | spin_lock_irqsave(&s->lock, flags); | 547 | spin_lock_irqsave(&s->lock, flags); |
547 | sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? | 548 | sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? |
548 | CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); | 549 | CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); |
549 | spin_unlock_irqrestore(&s->lock, flags); | 550 | spin_unlock_irqrestore(&s->lock, flags); |
550 | } | 551 | } |
551 | 552 | ||
552 | static void sccnxp_set_termios(struct uart_port *port, | 553 | static void sccnxp_set_termios(struct uart_port *port, |
553 | struct ktermios *termios, struct ktermios *old) | 554 | struct ktermios *termios, struct ktermios *old) |
554 | { | 555 | { |
555 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 556 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
556 | unsigned long flags; | 557 | unsigned long flags; |
557 | u8 mr1, mr2; | 558 | u8 mr1, mr2; |
558 | int baud; | 559 | int baud; |
559 | 560 | ||
560 | spin_lock_irqsave(&s->lock, flags); | 561 | spin_lock_irqsave(&s->lock, flags); |
561 | 562 | ||
562 | /* Mask termios capabilities we don't support */ | 563 | /* Mask termios capabilities we don't support */ |
563 | termios->c_cflag &= ~CMSPAR; | 564 | termios->c_cflag &= ~CMSPAR; |
564 | 565 | ||
565 | /* Disable RX & TX, reset break condition, status and FIFOs */ | 566 | /* Disable RX & TX, reset break condition, status and FIFOs */ |
566 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET | | 567 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET | |
567 | CR_RX_DISABLE | CR_TX_DISABLE); | 568 | CR_RX_DISABLE | CR_TX_DISABLE); |
568 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); | 569 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); |
569 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); | 570 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); |
570 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); | 571 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); |
571 | 572 | ||
572 | /* Word size */ | 573 | /* Word size */ |
573 | switch (termios->c_cflag & CSIZE) { | 574 | switch (termios->c_cflag & CSIZE) { |
574 | case CS5: | 575 | case CS5: |
575 | mr1 = MR1_BITS_5; | 576 | mr1 = MR1_BITS_5; |
576 | break; | 577 | break; |
577 | case CS6: | 578 | case CS6: |
578 | mr1 = MR1_BITS_6; | 579 | mr1 = MR1_BITS_6; |
579 | break; | 580 | break; |
580 | case CS7: | 581 | case CS7: |
581 | mr1 = MR1_BITS_7; | 582 | mr1 = MR1_BITS_7; |
582 | break; | 583 | break; |
583 | case CS8: | 584 | case CS8: |
584 | default: | 585 | default: |
585 | mr1 = MR1_BITS_8; | 586 | mr1 = MR1_BITS_8; |
586 | break; | 587 | break; |
587 | } | 588 | } |
588 | 589 | ||
589 | /* Parity */ | 590 | /* Parity */ |
590 | if (termios->c_cflag & PARENB) { | 591 | if (termios->c_cflag & PARENB) { |
591 | if (termios->c_cflag & PARODD) | 592 | if (termios->c_cflag & PARODD) |
592 | mr1 |= MR1_PAR_ODD; | 593 | mr1 |= MR1_PAR_ODD; |
593 | } else | 594 | } else |
594 | mr1 |= MR1_PAR_NO; | 595 | mr1 |= MR1_PAR_NO; |
595 | 596 | ||
596 | /* Stop bits */ | 597 | /* Stop bits */ |
597 | mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1; | 598 | mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1; |
598 | 599 | ||
599 | /* Update desired format */ | 600 | /* Update desired format */ |
600 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1); | 601 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1); |
601 | sccnxp_port_write(port, SCCNXP_MR_REG, mr1); | 602 | sccnxp_port_write(port, SCCNXP_MR_REG, mr1); |
602 | sccnxp_port_write(port, SCCNXP_MR_REG, mr2); | 603 | sccnxp_port_write(port, SCCNXP_MR_REG, mr2); |
603 | 604 | ||
604 | /* Set read status mask */ | 605 | /* Set read status mask */ |
605 | port->read_status_mask = SR_OVR; | 606 | port->read_status_mask = SR_OVR; |
606 | if (termios->c_iflag & INPCK) | 607 | if (termios->c_iflag & INPCK) |
607 | port->read_status_mask |= SR_PE | SR_FE; | 608 | port->read_status_mask |= SR_PE | SR_FE; |
608 | if (termios->c_iflag & (BRKINT | PARMRK)) | 609 | if (termios->c_iflag & (BRKINT | PARMRK)) |
609 | port->read_status_mask |= SR_BRK; | 610 | port->read_status_mask |= SR_BRK; |
610 | 611 | ||
611 | /* Set status ignore mask */ | 612 | /* Set status ignore mask */ |
612 | port->ignore_status_mask = 0; | 613 | port->ignore_status_mask = 0; |
613 | if (termios->c_iflag & IGNBRK) | 614 | if (termios->c_iflag & IGNBRK) |
614 | port->ignore_status_mask |= SR_BRK; | 615 | port->ignore_status_mask |= SR_BRK; |
615 | if (!(termios->c_cflag & CREAD)) | 616 | if (!(termios->c_cflag & CREAD)) |
616 | port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; | 617 | port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; |
617 | 618 | ||
618 | /* Setup baudrate */ | 619 | /* Setup baudrate */ |
619 | baud = uart_get_baud_rate(port, termios, old, 50, | 620 | baud = uart_get_baud_rate(port, termios, old, 50, |
620 | (s->flags & SCCNXP_HAVE_MR0) ? | 621 | (s->flags & SCCNXP_HAVE_MR0) ? |
621 | 230400 : 38400); | 622 | 230400 : 38400); |
622 | baud = sccnxp_set_baud(port, baud); | 623 | baud = sccnxp_set_baud(port, baud); |
623 | 624 | ||
624 | /* Update timeout according to new baud rate */ | 625 | /* Update timeout according to new baud rate */ |
625 | uart_update_timeout(port, termios->c_cflag, baud); | 626 | uart_update_timeout(port, termios->c_cflag, baud); |
626 | 627 | ||
627 | /* Report actual baudrate back to core */ | 628 | /* Report actual baudrate back to core */ |
628 | if (tty_termios_baud_rate(termios)) | 629 | if (tty_termios_baud_rate(termios)) |
629 | tty_termios_encode_baud_rate(termios, baud, baud); | 630 | tty_termios_encode_baud_rate(termios, baud, baud); |
630 | 631 | ||
631 | /* Enable RX & TX */ | 632 | /* Enable RX & TX */ |
632 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); | 633 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); |
633 | 634 | ||
634 | spin_unlock_irqrestore(&s->lock, flags); | 635 | spin_unlock_irqrestore(&s->lock, flags); |
635 | } | 636 | } |
636 | 637 | ||
637 | static int sccnxp_startup(struct uart_port *port) | 638 | static int sccnxp_startup(struct uart_port *port) |
638 | { | 639 | { |
639 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 640 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
640 | unsigned long flags; | 641 | unsigned long flags; |
641 | 642 | ||
642 | spin_lock_irqsave(&s->lock, flags); | 643 | spin_lock_irqsave(&s->lock, flags); |
643 | 644 | ||
644 | if (s->flags & SCCNXP_HAVE_IO) { | 645 | if (s->flags & SCCNXP_HAVE_IO) { |
645 | /* Outputs are controlled manually */ | 646 | /* Outputs are controlled manually */ |
646 | sccnxp_write(port, SCCNXP_OPCR_REG, 0); | 647 | sccnxp_write(port, SCCNXP_OPCR_REG, 0); |
647 | } | 648 | } |
648 | 649 | ||
649 | /* Reset break condition, status and FIFOs */ | 650 | /* Reset break condition, status and FIFOs */ |
650 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET); | 651 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET); |
651 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); | 652 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); |
652 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); | 653 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); |
653 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); | 654 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); |
654 | 655 | ||
655 | /* Enable RX & TX */ | 656 | /* Enable RX & TX */ |
656 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); | 657 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); |
657 | 658 | ||
658 | /* Enable RX interrupt */ | 659 | /* Enable RX interrupt */ |
659 | sccnxp_enable_irq(port, IMR_RXRDY); | 660 | sccnxp_enable_irq(port, IMR_RXRDY); |
660 | 661 | ||
661 | s->opened[port->line] = 1; | 662 | s->opened[port->line] = 1; |
662 | 663 | ||
663 | spin_unlock_irqrestore(&s->lock, flags); | 664 | spin_unlock_irqrestore(&s->lock, flags); |
664 | 665 | ||
665 | return 0; | 666 | return 0; |
666 | } | 667 | } |
667 | 668 | ||
668 | static void sccnxp_shutdown(struct uart_port *port) | 669 | static void sccnxp_shutdown(struct uart_port *port) |
669 | { | 670 | { |
670 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 671 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
671 | unsigned long flags; | 672 | unsigned long flags; |
672 | 673 | ||
673 | spin_lock_irqsave(&s->lock, flags); | 674 | spin_lock_irqsave(&s->lock, flags); |
674 | 675 | ||
675 | s->opened[port->line] = 0; | 676 | s->opened[port->line] = 0; |
676 | 677 | ||
677 | /* Disable interrupts */ | 678 | /* Disable interrupts */ |
678 | sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); | 679 | sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); |
679 | 680 | ||
680 | /* Disable TX & RX */ | 681 | /* Disable TX & RX */ |
681 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE); | 682 | sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE); |
682 | 683 | ||
683 | /* Leave direction to input */ | 684 | /* Leave direction to input */ |
684 | if (s->flags & SCCNXP_HAVE_IO) | 685 | if (s->flags & SCCNXP_HAVE_IO) |
685 | sccnxp_set_bit(port, DIR_OP, 0); | 686 | sccnxp_set_bit(port, DIR_OP, 0); |
686 | 687 | ||
687 | spin_unlock_irqrestore(&s->lock, flags); | 688 | spin_unlock_irqrestore(&s->lock, flags); |
688 | } | 689 | } |
689 | 690 | ||
690 | static const char *sccnxp_type(struct uart_port *port) | 691 | static const char *sccnxp_type(struct uart_port *port) |
691 | { | 692 | { |
692 | struct sccnxp_port *s = dev_get_drvdata(port->dev); | 693 | struct sccnxp_port *s = dev_get_drvdata(port->dev); |
693 | 694 | ||
694 | return (port->type == PORT_SC26XX) ? s->name : NULL; | 695 | return (port->type == PORT_SC26XX) ? s->name : NULL; |
695 | } | 696 | } |
696 | 697 | ||
697 | static void sccnxp_release_port(struct uart_port *port) | 698 | static void sccnxp_release_port(struct uart_port *port) |
698 | { | 699 | { |
699 | /* Do nothing */ | 700 | /* Do nothing */ |
700 | } | 701 | } |
701 | 702 | ||
702 | static int sccnxp_request_port(struct uart_port *port) | 703 | static int sccnxp_request_port(struct uart_port *port) |
703 | { | 704 | { |
704 | /* Do nothing */ | 705 | /* Do nothing */ |
705 | return 0; | 706 | return 0; |
706 | } | 707 | } |
707 | 708 | ||
708 | static void sccnxp_config_port(struct uart_port *port, int flags) | 709 | static void sccnxp_config_port(struct uart_port *port, int flags) |
709 | { | 710 | { |
710 | if (flags & UART_CONFIG_TYPE) | 711 | if (flags & UART_CONFIG_TYPE) |
711 | port->type = PORT_SC26XX; | 712 | port->type = PORT_SC26XX; |
712 | } | 713 | } |
713 | 714 | ||
714 | static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s) | 715 | static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s) |
715 | { | 716 | { |
716 | if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX)) | 717 | if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX)) |
717 | return 0; | 718 | return 0; |
718 | if (s->irq == port->irq) | 719 | if (s->irq == port->irq) |
719 | return 0; | 720 | return 0; |
720 | 721 | ||
721 | return -EINVAL; | 722 | return -EINVAL; |
722 | } | 723 | } |
723 | 724 | ||
724 | static const struct uart_ops sccnxp_ops = { | 725 | static const struct uart_ops sccnxp_ops = { |
725 | .tx_empty = sccnxp_tx_empty, | 726 | .tx_empty = sccnxp_tx_empty, |
726 | .set_mctrl = sccnxp_set_mctrl, | 727 | .set_mctrl = sccnxp_set_mctrl, |
727 | .get_mctrl = sccnxp_get_mctrl, | 728 | .get_mctrl = sccnxp_get_mctrl, |
728 | .stop_tx = sccnxp_stop_tx, | 729 | .stop_tx = sccnxp_stop_tx, |
729 | .start_tx = sccnxp_start_tx, | 730 | .start_tx = sccnxp_start_tx, |
730 | .stop_rx = sccnxp_stop_rx, | 731 | .stop_rx = sccnxp_stop_rx, |
731 | .enable_ms = sccnxp_enable_ms, | 732 | .enable_ms = sccnxp_enable_ms, |
732 | .break_ctl = sccnxp_break_ctl, | 733 | .break_ctl = sccnxp_break_ctl, |
733 | .startup = sccnxp_startup, | 734 | .startup = sccnxp_startup, |
734 | .shutdown = sccnxp_shutdown, | 735 | .shutdown = sccnxp_shutdown, |
735 | .set_termios = sccnxp_set_termios, | 736 | .set_termios = sccnxp_set_termios, |
736 | .type = sccnxp_type, | 737 | .type = sccnxp_type, |
737 | .release_port = sccnxp_release_port, | 738 | .release_port = sccnxp_release_port, |
738 | .request_port = sccnxp_request_port, | 739 | .request_port = sccnxp_request_port, |
739 | .config_port = sccnxp_config_port, | 740 | .config_port = sccnxp_config_port, |
740 | .verify_port = sccnxp_verify_port, | 741 | .verify_port = sccnxp_verify_port, |
741 | }; | 742 | }; |
742 | 743 | ||
743 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE | 744 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE |
744 | static void sccnxp_console_putchar(struct uart_port *port, int c) | 745 | static void sccnxp_console_putchar(struct uart_port *port, int c) |
745 | { | 746 | { |
746 | int tryes = 100000; | 747 | int tryes = 100000; |
747 | 748 | ||
748 | while (tryes--) { | 749 | while (tryes--) { |
749 | if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) { | 750 | if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) { |
750 | sccnxp_port_write(port, SCCNXP_THR_REG, c); | 751 | sccnxp_port_write(port, SCCNXP_THR_REG, c); |
751 | break; | 752 | break; |
752 | } | 753 | } |
753 | barrier(); | 754 | barrier(); |
754 | } | 755 | } |
755 | } | 756 | } |
756 | 757 | ||
757 | static void sccnxp_console_write(struct console *co, const char *c, unsigned n) | 758 | static void sccnxp_console_write(struct console *co, const char *c, unsigned n) |
758 | { | 759 | { |
759 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; | 760 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; |
760 | struct uart_port *port = &s->port[co->index]; | 761 | struct uart_port *port = &s->port[co->index]; |
761 | unsigned long flags; | 762 | unsigned long flags; |
762 | 763 | ||
763 | spin_lock_irqsave(&s->lock, flags); | 764 | spin_lock_irqsave(&s->lock, flags); |
764 | uart_console_write(port, c, n, sccnxp_console_putchar); | 765 | uart_console_write(port, c, n, sccnxp_console_putchar); |
765 | spin_unlock_irqrestore(&s->lock, flags); | 766 | spin_unlock_irqrestore(&s->lock, flags); |
766 | } | 767 | } |
767 | 768 | ||
768 | static int sccnxp_console_setup(struct console *co, char *options) | 769 | static int sccnxp_console_setup(struct console *co, char *options) |
769 | { | 770 | { |
770 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; | 771 | struct sccnxp_port *s = (struct sccnxp_port *)co->data; |
771 | struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; | 772 | struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; |
772 | int baud = 9600, bits = 8, parity = 'n', flow = 'n'; | 773 | int baud = 9600, bits = 8, parity = 'n', flow = 'n'; |
773 | 774 | ||
774 | if (options) | 775 | if (options) |
775 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 776 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
776 | 777 | ||
777 | return uart_set_options(port, co, baud, parity, bits, flow); | 778 | return uart_set_options(port, co, baud, parity, bits, flow); |
778 | } | 779 | } |
779 | #endif | 780 | #endif |
780 | 781 | ||
781 | static int sccnxp_probe(struct platform_device *pdev) | 782 | static int sccnxp_probe(struct platform_device *pdev) |
782 | { | 783 | { |
783 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 784 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
784 | int chiptype = pdev->id_entry->driver_data; | 785 | int chiptype = pdev->id_entry->driver_data; |
785 | struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); | 786 | struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); |
786 | int i, ret, fifosize, freq_min, freq_max; | 787 | int i, ret, fifosize, freq_min, freq_max, uartclk; |
787 | struct sccnxp_port *s; | 788 | struct sccnxp_port *s; |
788 | void __iomem *membase; | 789 | void __iomem *membase; |
790 | struct clk *clk; | ||
789 | 791 | ||
790 | membase = devm_ioremap_resource(&pdev->dev, res); | 792 | membase = devm_ioremap_resource(&pdev->dev, res); |
791 | if (IS_ERR(membase)) | 793 | if (IS_ERR(membase)) |
792 | return PTR_ERR(membase); | 794 | return PTR_ERR(membase); |
793 | 795 | ||
794 | s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); | 796 | s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); |
795 | if (!s) { | 797 | if (!s) { |
796 | dev_err(&pdev->dev, "Error allocating port structure\n"); | 798 | dev_err(&pdev->dev, "Error allocating port structure\n"); |
797 | return -ENOMEM; | 799 | return -ENOMEM; |
798 | } | 800 | } |
799 | platform_set_drvdata(pdev, s); | 801 | platform_set_drvdata(pdev, s); |
800 | 802 | ||
801 | spin_lock_init(&s->lock); | 803 | spin_lock_init(&s->lock); |
802 | 804 | ||
803 | /* Individual chip settings */ | 805 | /* Individual chip settings */ |
804 | switch (chiptype) { | 806 | switch (chiptype) { |
805 | case SCCNXP_TYPE_SC2681: | 807 | case SCCNXP_TYPE_SC2681: |
806 | s->name = "SC2681"; | 808 | s->name = "SC2681"; |
807 | s->uart.nr = 2; | 809 | s->uart.nr = 2; |
808 | s->freq_std = 3686400; | 810 | s->freq_std = 3686400; |
809 | s->addr_mask = 0x0f; | 811 | s->addr_mask = 0x0f; |
810 | s->flags = SCCNXP_HAVE_IO; | 812 | s->flags = SCCNXP_HAVE_IO; |
811 | fifosize = 3; | 813 | fifosize = 3; |
812 | freq_min = 1000000; | 814 | freq_min = 1000000; |
813 | freq_max = 4000000; | 815 | freq_max = 4000000; |
814 | break; | 816 | break; |
815 | case SCCNXP_TYPE_SC2691: | 817 | case SCCNXP_TYPE_SC2691: |
816 | s->name = "SC2691"; | 818 | s->name = "SC2691"; |
817 | s->uart.nr = 1; | 819 | s->uart.nr = 1; |
818 | s->freq_std = 3686400; | 820 | s->freq_std = 3686400; |
819 | s->addr_mask = 0x07; | 821 | s->addr_mask = 0x07; |
820 | s->flags = 0; | 822 | s->flags = 0; |
821 | fifosize = 3; | 823 | fifosize = 3; |
822 | freq_min = 1000000; | 824 | freq_min = 1000000; |
823 | freq_max = 4000000; | 825 | freq_max = 4000000; |
824 | break; | 826 | break; |
825 | case SCCNXP_TYPE_SC2692: | 827 | case SCCNXP_TYPE_SC2692: |
826 | s->name = "SC2692"; | 828 | s->name = "SC2692"; |
827 | s->uart.nr = 2; | 829 | s->uart.nr = 2; |
828 | s->freq_std = 3686400; | 830 | s->freq_std = 3686400; |
829 | s->addr_mask = 0x0f; | 831 | s->addr_mask = 0x0f; |
830 | s->flags = SCCNXP_HAVE_IO; | 832 | s->flags = SCCNXP_HAVE_IO; |
831 | fifosize = 3; | 833 | fifosize = 3; |
832 | freq_min = 1000000; | 834 | freq_min = 1000000; |
833 | freq_max = 4000000; | 835 | freq_max = 4000000; |
834 | break; | 836 | break; |
835 | case SCCNXP_TYPE_SC2891: | 837 | case SCCNXP_TYPE_SC2891: |
836 | s->name = "SC2891"; | 838 | s->name = "SC2891"; |
837 | s->uart.nr = 1; | 839 | s->uart.nr = 1; |
838 | s->freq_std = 3686400; | 840 | s->freq_std = 3686400; |
839 | s->addr_mask = 0x0f; | 841 | s->addr_mask = 0x0f; |
840 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; | 842 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; |
841 | fifosize = 16; | 843 | fifosize = 16; |
842 | freq_min = 100000; | 844 | freq_min = 100000; |
843 | freq_max = 8000000; | 845 | freq_max = 8000000; |
844 | break; | 846 | break; |
845 | case SCCNXP_TYPE_SC2892: | 847 | case SCCNXP_TYPE_SC2892: |
846 | s->name = "SC2892"; | 848 | s->name = "SC2892"; |
847 | s->uart.nr = 2; | 849 | s->uart.nr = 2; |
848 | s->freq_std = 3686400; | 850 | s->freq_std = 3686400; |
849 | s->addr_mask = 0x0f; | 851 | s->addr_mask = 0x0f; |
850 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; | 852 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; |
851 | fifosize = 16; | 853 | fifosize = 16; |
852 | freq_min = 100000; | 854 | freq_min = 100000; |
853 | freq_max = 8000000; | 855 | freq_max = 8000000; |
854 | break; | 856 | break; |
855 | case SCCNXP_TYPE_SC28202: | 857 | case SCCNXP_TYPE_SC28202: |
856 | s->name = "SC28202"; | 858 | s->name = "SC28202"; |
857 | s->uart.nr = 2; | 859 | s->uart.nr = 2; |
858 | s->freq_std = 14745600; | 860 | s->freq_std = 14745600; |
859 | s->addr_mask = 0x7f; | 861 | s->addr_mask = 0x7f; |
860 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; | 862 | s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; |
861 | fifosize = 256; | 863 | fifosize = 256; |
862 | freq_min = 1000000; | 864 | freq_min = 1000000; |
863 | freq_max = 50000000; | 865 | freq_max = 50000000; |
864 | break; | 866 | break; |
865 | case SCCNXP_TYPE_SC68681: | 867 | case SCCNXP_TYPE_SC68681: |
866 | s->name = "SC68681"; | 868 | s->name = "SC68681"; |
867 | s->uart.nr = 2; | 869 | s->uart.nr = 2; |
868 | s->freq_std = 3686400; | 870 | s->freq_std = 3686400; |
869 | s->addr_mask = 0x0f; | 871 | s->addr_mask = 0x0f; |
870 | s->flags = SCCNXP_HAVE_IO; | 872 | s->flags = SCCNXP_HAVE_IO; |
871 | fifosize = 3; | 873 | fifosize = 3; |
872 | freq_min = 1000000; | 874 | freq_min = 1000000; |
873 | freq_max = 4000000; | 875 | freq_max = 4000000; |
874 | break; | 876 | break; |
875 | case SCCNXP_TYPE_SC68692: | 877 | case SCCNXP_TYPE_SC68692: |
876 | s->name = "SC68692"; | 878 | s->name = "SC68692"; |
877 | s->uart.nr = 2; | 879 | s->uart.nr = 2; |
878 | s->freq_std = 3686400; | 880 | s->freq_std = 3686400; |
879 | s->addr_mask = 0x0f; | 881 | s->addr_mask = 0x0f; |
880 | s->flags = SCCNXP_HAVE_IO; | 882 | s->flags = SCCNXP_HAVE_IO; |
881 | fifosize = 3; | 883 | fifosize = 3; |
882 | freq_min = 1000000; | 884 | freq_min = 1000000; |
883 | freq_max = 4000000; | 885 | freq_max = 4000000; |
884 | break; | 886 | break; |
885 | default: | 887 | default: |
886 | dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); | 888 | dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); |
887 | return -ENOTSUPP; | 889 | return -ENOTSUPP; |
888 | } | 890 | } |
889 | 891 | ||
890 | s->regulator = devm_regulator_get(&pdev->dev, "vcc"); | 892 | s->regulator = devm_regulator_get(&pdev->dev, "vcc"); |
891 | if (!IS_ERR(s->regulator)) { | 893 | if (!IS_ERR(s->regulator)) { |
892 | ret = regulator_enable(s->regulator); | 894 | ret = regulator_enable(s->regulator); |
893 | if (ret) { | 895 | if (ret) { |
894 | dev_err(&pdev->dev, | 896 | dev_err(&pdev->dev, |
895 | "Failed to enable regulator: %i\n", ret); | 897 | "Failed to enable regulator: %i\n", ret); |
896 | return ret; | 898 | return ret; |
897 | } | 899 | } |
898 | } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER) | 900 | } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER) |
899 | return -EPROBE_DEFER; | 901 | return -EPROBE_DEFER; |
900 | 902 | ||
901 | if (!pdata) { | 903 | clk = devm_clk_get(&pdev->dev, NULL); |
902 | dev_warn(&pdev->dev, | 904 | if (IS_ERR(clk)) { |
903 | "No platform data supplied, using defaults\n"); | 905 | if (PTR_ERR(clk) == -EPROBE_DEFER) { |
904 | s->pdata.frequency = s->freq_std; | 906 | ret = -EPROBE_DEFER; |
907 | goto err_out; | ||
908 | } | ||
909 | dev_notice(&pdev->dev, "Using default clock frequency\n"); | ||
910 | uartclk = s->freq_std; | ||
905 | } else | 911 | } else |
912 | uartclk = clk_get_rate(clk); | ||
913 | |||
914 | /* Check input frequency */ | ||
915 | if ((uartclk < freq_min) || (uartclk > freq_max)) { | ||
916 | dev_err(&pdev->dev, "Frequency out of bounds\n"); | ||
917 | ret = -EINVAL; | ||
918 | goto err_out; | ||
919 | } | ||
920 | |||
921 | if (pdata) | ||
906 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); | 922 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); |
907 | 923 | ||
908 | if (s->pdata.poll_time_us) { | 924 | if (s->pdata.poll_time_us) { |
909 | dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", | 925 | dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", |
910 | s->pdata.poll_time_us); | 926 | s->pdata.poll_time_us); |
911 | s->poll = 1; | 927 | s->poll = 1; |
912 | } | 928 | } |
913 | 929 | ||
914 | if (!s->poll) { | 930 | if (!s->poll) { |
915 | s->irq = platform_get_irq(pdev, 0); | 931 | s->irq = platform_get_irq(pdev, 0); |
916 | if (s->irq < 0) { | 932 | if (s->irq < 0) { |
917 | dev_err(&pdev->dev, "Missing irq resource data\n"); | 933 | dev_err(&pdev->dev, "Missing irq resource data\n"); |
918 | ret = -ENXIO; | 934 | ret = -ENXIO; |
919 | goto err_out; | 935 | goto err_out; |
920 | } | 936 | } |
921 | } | 937 | } |
922 | 938 | ||
923 | /* Check input frequency */ | ||
924 | if ((s->pdata.frequency < freq_min) || | ||
925 | (s->pdata.frequency > freq_max)) { | ||
926 | dev_err(&pdev->dev, "Frequency out of bounds\n"); | ||
927 | ret = -EINVAL; | ||
928 | goto err_out; | ||
929 | } | ||
930 | |||
931 | s->uart.owner = THIS_MODULE; | 939 | s->uart.owner = THIS_MODULE; |
932 | s->uart.dev_name = "ttySC"; | 940 | s->uart.dev_name = "ttySC"; |
933 | s->uart.major = SCCNXP_MAJOR; | 941 | s->uart.major = SCCNXP_MAJOR; |
934 | s->uart.minor = SCCNXP_MINOR; | 942 | s->uart.minor = SCCNXP_MINOR; |
935 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE | 943 | #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE |
936 | s->uart.cons = &s->console; | 944 | s->uart.cons = &s->console; |
937 | s->uart.cons->device = uart_console_device; | 945 | s->uart.cons->device = uart_console_device; |
938 | s->uart.cons->write = sccnxp_console_write; | 946 | s->uart.cons->write = sccnxp_console_write; |
939 | s->uart.cons->setup = sccnxp_console_setup; | 947 | s->uart.cons->setup = sccnxp_console_setup; |
940 | s->uart.cons->flags = CON_PRINTBUFFER; | 948 | s->uart.cons->flags = CON_PRINTBUFFER; |
941 | s->uart.cons->index = -1; | 949 | s->uart.cons->index = -1; |
942 | s->uart.cons->data = s; | 950 | s->uart.cons->data = s; |
943 | strcpy(s->uart.cons->name, "ttySC"); | 951 | strcpy(s->uart.cons->name, "ttySC"); |
944 | #endif | 952 | #endif |
945 | ret = uart_register_driver(&s->uart); | 953 | ret = uart_register_driver(&s->uart); |
946 | if (ret) { | 954 | if (ret) { |
947 | dev_err(&pdev->dev, "Registering UART driver failed\n"); | 955 | dev_err(&pdev->dev, "Registering UART driver failed\n"); |
948 | goto err_out; | 956 | goto err_out; |
949 | } | 957 | } |
950 | 958 | ||
951 | for (i = 0; i < s->uart.nr; i++) { | 959 | for (i = 0; i < s->uart.nr; i++) { |
952 | s->port[i].line = i; | 960 | s->port[i].line = i; |
953 | s->port[i].dev = &pdev->dev; | 961 | s->port[i].dev = &pdev->dev; |
954 | s->port[i].irq = s->irq; | 962 | s->port[i].irq = s->irq; |
955 | s->port[i].type = PORT_SC26XX; | 963 | s->port[i].type = PORT_SC26XX; |
956 | s->port[i].fifosize = fifosize; | 964 | s->port[i].fifosize = fifosize; |
957 | s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; | 965 | s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; |
958 | s->port[i].iotype = UPIO_MEM; | 966 | s->port[i].iotype = UPIO_MEM; |
959 | s->port[i].mapbase = res->start; | 967 | s->port[i].mapbase = res->start; |
960 | s->port[i].membase = membase; | 968 | s->port[i].membase = membase; |
961 | s->port[i].regshift = s->pdata.reg_shift; | 969 | s->port[i].regshift = s->pdata.reg_shift; |
962 | s->port[i].uartclk = s->pdata.frequency; | 970 | s->port[i].uartclk = uartclk; |
963 | s->port[i].ops = &sccnxp_ops; | 971 | s->port[i].ops = &sccnxp_ops; |
964 | uart_add_one_port(&s->uart, &s->port[i]); | 972 | uart_add_one_port(&s->uart, &s->port[i]); |
965 | /* Set direction to input */ | 973 | /* Set direction to input */ |
966 | if (s->flags & SCCNXP_HAVE_IO) | 974 | if (s->flags & SCCNXP_HAVE_IO) |
967 | sccnxp_set_bit(&s->port[i], DIR_OP, 0); | 975 | sccnxp_set_bit(&s->port[i], DIR_OP, 0); |
968 | } | 976 | } |
969 | 977 | ||
970 | /* Disable interrupts */ | 978 | /* Disable interrupts */ |
971 | s->imr = 0; | 979 | s->imr = 0; |
972 | sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0); | 980 | sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0); |
973 | 981 | ||
974 | if (!s->poll) { | 982 | if (!s->poll) { |
975 | ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, | 983 | ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, |
976 | sccnxp_ist, | 984 | sccnxp_ist, |
977 | IRQF_TRIGGER_FALLING | | 985 | IRQF_TRIGGER_FALLING | |
978 | IRQF_ONESHOT, | 986 | IRQF_ONESHOT, |
979 | dev_name(&pdev->dev), s); | 987 | dev_name(&pdev->dev), s); |
980 | if (!ret) | 988 | if (!ret) |
981 | return 0; | 989 | return 0; |
982 | 990 | ||
983 | dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); | 991 | dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); |
984 | } else { | 992 | } else { |
985 | init_timer(&s->timer); | 993 | init_timer(&s->timer); |
986 | setup_timer(&s->timer, sccnxp_timer, (unsigned long)s); | 994 | setup_timer(&s->timer, sccnxp_timer, (unsigned long)s); |
987 | mod_timer(&s->timer, jiffies + | 995 | mod_timer(&s->timer, jiffies + |
988 | usecs_to_jiffies(s->pdata.poll_time_us)); | 996 | usecs_to_jiffies(s->pdata.poll_time_us)); |
989 | return 0; | 997 | return 0; |
990 | } | 998 | } |
991 | 999 | ||
992 | err_out: | 1000 | err_out: |
993 | if (!IS_ERR(s->regulator)) | 1001 | if (!IS_ERR(s->regulator)) |
994 | return regulator_disable(s->regulator); | 1002 | return regulator_disable(s->regulator); |
995 | 1003 | ||
996 | return ret; | 1004 | return ret; |
997 | } | 1005 | } |
998 | 1006 | ||
999 | static int sccnxp_remove(struct platform_device *pdev) | 1007 | static int sccnxp_remove(struct platform_device *pdev) |
1000 | { | 1008 | { |
1001 | int i; | 1009 | int i; |
1002 | struct sccnxp_port *s = platform_get_drvdata(pdev); | 1010 | struct sccnxp_port *s = platform_get_drvdata(pdev); |
1003 | 1011 | ||
1004 | if (!s->poll) | 1012 | if (!s->poll) |
1005 | devm_free_irq(&pdev->dev, s->irq, s); | 1013 | devm_free_irq(&pdev->dev, s->irq, s); |
1006 | else | 1014 | else |
1007 | del_timer_sync(&s->timer); | 1015 | del_timer_sync(&s->timer); |
1008 | 1016 | ||
1009 | for (i = 0; i < s->uart.nr; i++) | 1017 | for (i = 0; i < s->uart.nr; i++) |
1010 | uart_remove_one_port(&s->uart, &s->port[i]); | 1018 | uart_remove_one_port(&s->uart, &s->port[i]); |
1011 | 1019 | ||
1012 | uart_unregister_driver(&s->uart); | 1020 | uart_unregister_driver(&s->uart); |
1013 | 1021 | ||
1014 | if (!IS_ERR(s->regulator)) | 1022 | if (!IS_ERR(s->regulator)) |
1015 | return regulator_disable(s->regulator); | 1023 | return regulator_disable(s->regulator); |
1016 | 1024 | ||
1017 | return 0; | 1025 | return 0; |
1018 | } | 1026 | } |
1019 | 1027 | ||
1020 | static const struct platform_device_id sccnxp_id_table[] = { | 1028 | static const struct platform_device_id sccnxp_id_table[] = { |
1021 | { "sc2681", SCCNXP_TYPE_SC2681 }, | 1029 | { "sc2681", SCCNXP_TYPE_SC2681 }, |
1022 | { "sc2691", SCCNXP_TYPE_SC2691 }, | 1030 | { "sc2691", SCCNXP_TYPE_SC2691 }, |
1023 | { "sc2692", SCCNXP_TYPE_SC2692 }, | 1031 | { "sc2692", SCCNXP_TYPE_SC2692 }, |
1024 | { "sc2891", SCCNXP_TYPE_SC2891 }, | 1032 | { "sc2891", SCCNXP_TYPE_SC2891 }, |
1025 | { "sc2892", SCCNXP_TYPE_SC2892 }, | 1033 | { "sc2892", SCCNXP_TYPE_SC2892 }, |
1026 | { "sc28202", SCCNXP_TYPE_SC28202 }, | 1034 | { "sc28202", SCCNXP_TYPE_SC28202 }, |
1027 | { "sc68681", SCCNXP_TYPE_SC68681 }, | 1035 | { "sc68681", SCCNXP_TYPE_SC68681 }, |
1028 | { "sc68692", SCCNXP_TYPE_SC68692 }, | 1036 | { "sc68692", SCCNXP_TYPE_SC68692 }, |
1029 | { }, | 1037 | { }, |
1030 | }; | 1038 | }; |
1031 | MODULE_DEVICE_TABLE(platform, sccnxp_id_table); | 1039 | MODULE_DEVICE_TABLE(platform, sccnxp_id_table); |
1032 | 1040 | ||
1033 | static struct platform_driver sccnxp_uart_driver = { | 1041 | static struct platform_driver sccnxp_uart_driver = { |
1034 | .driver = { | 1042 | .driver = { |
1035 | .name = SCCNXP_NAME, | 1043 | .name = SCCNXP_NAME, |
1036 | .owner = THIS_MODULE, | 1044 | .owner = THIS_MODULE, |
1037 | }, | 1045 | }, |
1038 | .probe = sccnxp_probe, | 1046 | .probe = sccnxp_probe, |
1039 | .remove = sccnxp_remove, | 1047 | .remove = sccnxp_remove, |
include/linux/platform_data/serial-sccnxp.h
1 | /* | 1 | /* |
2 | * NXP (Philips) SCC+++(SCN+++) serial driver | 2 | * NXP (Philips) SCC+++(SCN+++) serial driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | 4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> |
5 | * | 5 | * |
6 | * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) | 6 | * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 10 | * the Free Software Foundation; either version 2 of the License, or |
11 | * (at your option) any later version. | 11 | * (at your option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #ifndef _PLATFORM_DATA_SERIAL_SCCNXP_H_ | 14 | #ifndef _PLATFORM_DATA_SERIAL_SCCNXP_H_ |
15 | #define _PLATFORM_DATA_SERIAL_SCCNXP_H_ | 15 | #define _PLATFORM_DATA_SERIAL_SCCNXP_H_ |
16 | 16 | ||
17 | #define SCCNXP_MAX_UARTS 2 | 17 | #define SCCNXP_MAX_UARTS 2 |
18 | 18 | ||
19 | /* Output lines */ | 19 | /* Output lines */ |
20 | #define LINE_OP0 1 | 20 | #define LINE_OP0 1 |
21 | #define LINE_OP1 2 | 21 | #define LINE_OP1 2 |
22 | #define LINE_OP2 3 | 22 | #define LINE_OP2 3 |
23 | #define LINE_OP3 4 | 23 | #define LINE_OP3 4 |
24 | #define LINE_OP4 5 | 24 | #define LINE_OP4 5 |
25 | #define LINE_OP5 6 | 25 | #define LINE_OP5 6 |
26 | #define LINE_OP6 7 | 26 | #define LINE_OP6 7 |
27 | #define LINE_OP7 8 | 27 | #define LINE_OP7 8 |
28 | 28 | ||
29 | /* Input lines */ | 29 | /* Input lines */ |
30 | #define LINE_IP0 9 | 30 | #define LINE_IP0 9 |
31 | #define LINE_IP1 10 | 31 | #define LINE_IP1 10 |
32 | #define LINE_IP2 11 | 32 | #define LINE_IP2 11 |
33 | #define LINE_IP3 12 | 33 | #define LINE_IP3 12 |
34 | #define LINE_IP4 13 | 34 | #define LINE_IP4 13 |
35 | #define LINE_IP5 14 | 35 | #define LINE_IP5 14 |
36 | #define LINE_IP6 15 | 36 | #define LINE_IP6 15 |
37 | 37 | ||
38 | /* Signals */ | 38 | /* Signals */ |
39 | #define DTR_OP 0 /* DTR */ | 39 | #define DTR_OP 0 /* DTR */ |
40 | #define RTS_OP 4 /* RTS */ | 40 | #define RTS_OP 4 /* RTS */ |
41 | #define DSR_IP 8 /* DSR */ | 41 | #define DSR_IP 8 /* DSR */ |
42 | #define CTS_IP 12 /* CTS */ | 42 | #define CTS_IP 12 /* CTS */ |
43 | #define DCD_IP 16 /* DCD */ | 43 | #define DCD_IP 16 /* DCD */ |
44 | #define RNG_IP 20 /* RNG */ | 44 | #define RNG_IP 20 /* RNG */ |
45 | 45 | ||
46 | #define DIR_OP 24 /* Special signal for control RS-485. | 46 | #define DIR_OP 24 /* Special signal for control RS-485. |
47 | * Goes high when transmit, | 47 | * Goes high when transmit, |
48 | * then goes low. | 48 | * then goes low. |
49 | */ | 49 | */ |
50 | 50 | ||
51 | /* Routing control signal 'sig' to line 'line' */ | 51 | /* Routing control signal 'sig' to line 'line' */ |
52 | #define MCTRL_SIG(sig, line) ((line) << (sig)) | 52 | #define MCTRL_SIG(sig, line) ((line) << (sig)) |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Example board initialization data: | 55 | * Example board initialization data: |
56 | * | 56 | * |
57 | * static struct resource sc2892_resources[] = { | 57 | * static struct resource sc2892_resources[] = { |
58 | * DEFINE_RES_MEM(UART_PHYS_START, 0x10), | 58 | * DEFINE_RES_MEM(UART_PHYS_START, 0x10), |
59 | * DEFINE_RES_IRQ(IRQ_EXT2), | 59 | * DEFINE_RES_IRQ(IRQ_EXT2), |
60 | * }; | 60 | * }; |
61 | * | 61 | * |
62 | * static struct sccnxp_pdata sc2892_info = { | 62 | * static struct sccnxp_pdata sc2892_info = { |
63 | * .frequency = 3686400, | ||
64 | * .mctrl_cfg[0] = MCTRL_SIG(DIR_OP, LINE_OP0), | 63 | * .mctrl_cfg[0] = MCTRL_SIG(DIR_OP, LINE_OP0), |
65 | * .mctrl_cfg[1] = MCTRL_SIG(DIR_OP, LINE_OP1), | 64 | * .mctrl_cfg[1] = MCTRL_SIG(DIR_OP, LINE_OP1), |
66 | * }; | 65 | * }; |
67 | * | 66 | * |
68 | * static struct platform_device sc2892 = { | 67 | * static struct platform_device sc2892 = { |
69 | * .name = "sc2892", | 68 | * .name = "sc2892", |
70 | * .id = -1, | 69 | * .id = -1, |
71 | * .resource = sc2892_resources, | 70 | * .resource = sc2892_resources, |
72 | * .num_resources = ARRAY_SIZE(sc2892_resources), | 71 | * .num_resources = ARRAY_SIZE(sc2892_resources), |
73 | * .dev = { | 72 | * .dev = { |
74 | * .platform_data = &sc2892_info, | 73 | * .platform_data = &sc2892_info, |
75 | * }, | 74 | * }, |
76 | * }; | 75 | * }; |
77 | */ | 76 | */ |
78 | 77 | ||
79 | /* SCCNXP platform data structure */ | 78 | /* SCCNXP platform data structure */ |
80 | struct sccnxp_pdata { | 79 | struct sccnxp_pdata { |
81 | /* Frequency (extrenal clock or crystal) */ | ||
82 | int frequency; | ||
83 | /* Shift for A0 line */ | 80 | /* Shift for A0 line */ |
84 | const u8 reg_shift; | 81 | const u8 reg_shift; |
85 | /* Modem control lines configuration */ | 82 | /* Modem control lines configuration */ |
86 | const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; | 83 | const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; |
87 | /* Timer value for polling mode (usecs) */ | 84 | /* Timer value for polling mode (usecs) */ |
88 | const unsigned int poll_time_us; | 85 | const unsigned int poll_time_us; |
89 | }; | 86 | }; |
90 | 87 | ||
91 | #endif | 88 | #endif |
92 | 89 |