diff options
Diffstat (limited to 'drivers/tty/serial/efm32-uart.c')
-rw-r--r-- | drivers/tty/serial/efm32-uart.c | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index a8cbb2670521..7d199c8e1a75 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c | |||
@@ -81,6 +81,7 @@ struct efm32_uart_port { | |||
81 | struct uart_port port; | 81 | struct uart_port port; |
82 | unsigned int txirq; | 82 | unsigned int txirq; |
83 | struct clk *clk; | 83 | struct clk *clk; |
84 | struct efm32_uart_pdata pdata; | ||
84 | }; | 85 | }; |
85 | #define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) | 86 | #define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) |
86 | #define efm_debug(efm_port, format, arg...) \ | 87 | #define efm_debug(efm_port, format, arg...) \ |
@@ -194,8 +195,7 @@ static void efm32_uart_break_ctl(struct uart_port *port, int ctl) | |||
194 | /* not possible without fiddling with gpios */ | 195 | /* not possible without fiddling with gpios */ |
195 | } | 196 | } |
196 | 197 | ||
197 | static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port, | 198 | static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port) |
198 | struct tty_struct *tty) | ||
199 | { | 199 | { |
200 | struct uart_port *port = &efm_port->port; | 200 | struct uart_port *port = &efm_port->port; |
201 | 201 | ||
@@ -237,8 +237,8 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port, | |||
237 | rxdata & UARTn_RXDATAX_RXDATA__MASK)) | 237 | rxdata & UARTn_RXDATAX_RXDATA__MASK)) |
238 | continue; | 238 | continue; |
239 | 239 | ||
240 | if (tty && (rxdata & port->ignore_status_mask) == 0) | 240 | if ((rxdata & port->ignore_status_mask) == 0) |
241 | tty_insert_flip_char(tty, | 241 | tty_insert_flip_char(&port->state->port, |
242 | rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); | 242 | rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); |
243 | } | 243 | } |
244 | } | 244 | } |
@@ -249,15 +249,13 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data) | |||
249 | u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); | 249 | u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); |
250 | int handled = IRQ_NONE; | 250 | int handled = IRQ_NONE; |
251 | struct uart_port *port = &efm_port->port; | 251 | struct uart_port *port = &efm_port->port; |
252 | struct tty_struct *tty; | 252 | struct tty_port *tport = &port->state->port; |
253 | 253 | ||
254 | spin_lock(&port->lock); | 254 | spin_lock(&port->lock); |
255 | 255 | ||
256 | tty = tty_kref_get(port->state->port.tty); | ||
257 | |||
258 | if (irqflag & UARTn_IF_RXDATAV) { | 256 | if (irqflag & UARTn_IF_RXDATAV) { |
259 | efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); | 257 | efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); |
260 | efm32_uart_rx_chars(efm_port, tty); | 258 | efm32_uart_rx_chars(efm_port); |
261 | 259 | ||
262 | handled = IRQ_HANDLED; | 260 | handled = IRQ_HANDLED; |
263 | } | 261 | } |
@@ -265,16 +263,12 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data) | |||
265 | if (irqflag & UARTn_IF_RXOF) { | 263 | if (irqflag & UARTn_IF_RXOF) { |
266 | efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); | 264 | efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); |
267 | port->icount.overrun++; | 265 | port->icount.overrun++; |
268 | if (tty) | 266 | tty_insert_flip_char(tport, 0, TTY_OVERRUN); |
269 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
270 | 267 | ||
271 | handled = IRQ_HANDLED; | 268 | handled = IRQ_HANDLED; |
272 | } | 269 | } |
273 | 270 | ||
274 | if (tty) { | 271 | tty_flip_buffer_push(tport); |
275 | tty_flip_buffer_push(tty); | ||
276 | tty_kref_put(tty); | ||
277 | } | ||
278 | 272 | ||
279 | spin_unlock(&port->lock); | 273 | spin_unlock(&port->lock); |
280 | 274 | ||
@@ -300,13 +294,8 @@ static irqreturn_t efm32_uart_txirq(int irq, void *data) | |||
300 | static int efm32_uart_startup(struct uart_port *port) | 294 | static int efm32_uart_startup(struct uart_port *port) |
301 | { | 295 | { |
302 | struct efm32_uart_port *efm_port = to_efm_port(port); | 296 | struct efm32_uart_port *efm_port = to_efm_port(port); |
303 | u32 location = 0; | ||
304 | struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev); | ||
305 | int ret; | 297 | int ret; |
306 | 298 | ||
307 | if (pdata) | ||
308 | location = UARTn_ROUTE_LOCATION(pdata->location); | ||
309 | |||
310 | ret = clk_enable(efm_port->clk); | 299 | ret = clk_enable(efm_port->clk); |
311 | if (ret) { | 300 | if (ret) { |
312 | efm_debug(efm_port, "failed to enable clk\n"); | 301 | efm_debug(efm_port, "failed to enable clk\n"); |
@@ -315,7 +304,9 @@ static int efm32_uart_startup(struct uart_port *port) | |||
315 | port->uartclk = clk_get_rate(efm_port->clk); | 304 | port->uartclk = clk_get_rate(efm_port->clk); |
316 | 305 | ||
317 | /* Enable pins at configured location */ | 306 | /* Enable pins at configured location */ |
318 | efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, | 307 | efm32_uart_write32(efm_port, |
308 | UARTn_ROUTE_LOCATION(efm_port->pdata.location) | | ||
309 | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, | ||
319 | UARTn_ROUTE); | 310 | UARTn_ROUTE); |
320 | 311 | ||
321 | ret = request_irq(port->irq, efm32_uart_rxirq, 0, | 312 | ret = request_irq(port->irq, efm32_uart_rxirq, 0, |
@@ -674,11 +665,24 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, | |||
674 | struct efm32_uart_port *efm_port) | 665 | struct efm32_uart_port *efm_port) |
675 | { | 666 | { |
676 | struct device_node *np = pdev->dev.of_node; | 667 | struct device_node *np = pdev->dev.of_node; |
668 | u32 location; | ||
677 | int ret; | 669 | int ret; |
678 | 670 | ||
679 | if (!np) | 671 | if (!np) |
680 | return 1; | 672 | return 1; |
681 | 673 | ||
674 | ret = of_property_read_u32(np, "location", &location); | ||
675 | if (!ret) { | ||
676 | if (location > 5) { | ||
677 | dev_err(&pdev->dev, "invalid location\n"); | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | efm_debug(efm_port, "using location %u\n", location); | ||
681 | efm_port->pdata.location = location; | ||
682 | } else { | ||
683 | efm_debug(efm_port, "fall back to location 0\n"); | ||
684 | } | ||
685 | |||
682 | ret = of_alias_get_id(np, "serial"); | 686 | ret = of_alias_get_id(np, "serial"); |
683 | if (ret < 0) { | 687 | if (ret < 0) { |
684 | dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); | 688 | dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); |
@@ -738,10 +742,16 @@ static int efm32_uart_probe(struct platform_device *pdev) | |||
738 | efm_port->port.flags = UPF_BOOT_AUTOCONF; | 742 | efm_port->port.flags = UPF_BOOT_AUTOCONF; |
739 | 743 | ||
740 | ret = efm32_uart_probe_dt(pdev, efm_port); | 744 | ret = efm32_uart_probe_dt(pdev, efm_port); |
741 | if (ret > 0) | 745 | if (ret > 0) { |
742 | /* not created by device tree */ | 746 | /* not created by device tree */ |
747 | const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev); | ||
748 | |||
743 | efm_port->port.line = pdev->id; | 749 | efm_port->port.line = pdev->id; |
744 | 750 | ||
751 | if (pdata) | ||
752 | efm_port->pdata = *pdata; | ||
753 | } | ||
754 | |||
745 | if (efm_port->port.line >= 0 && | 755 | if (efm_port->port.line >= 0 && |
746 | efm_port->port.line < ARRAY_SIZE(efm32_uart_ports)) | 756 | efm_port->port.line < ARRAY_SIZE(efm32_uart_ports)) |
747 | efm32_uart_ports[efm_port->port.line] = efm_port; | 757 | efm32_uart_ports[efm_port->port.line] = efm_port; |