aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSoren Brinkmann <soren.brinkmann@xilinx.com>2013-10-17 17:08:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-19 22:47:38 -0400
commitc4b0510cc1571ff44e1d6024d92683d49a8bcfde (patch)
treeb82057687f759d1f64664a177a7df96cc62b92bb
parente6b39bfd0db207d2e9f3f78468d18f529f3b7901 (diff)
tty: xuartps: Dynamically adjust to input frequency changes
Add a clock notifier to dynamically handle frequency changes of the input clock by reprogramming the UART in order to keep the baud rate constant. Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/xilinx_uartps.c123
1 files changed, 119 insertions, 4 deletions
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 95e12c216984..82195040e906 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -163,13 +163,20 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
163 163
164/** 164/**
165 * struct xuartps - device data 165 * struct xuartps - device data
166 * @refclk Reference clock 166 * @port Pointer to the UART port
167 * @aperclk APB clock 167 * @refclk Reference clock
168 * @aperclk APB clock
169 * @baud Current baud rate
170 * @clk_rate_change_nb Notifier block for clock changes
168 */ 171 */
169struct xuartps { 172struct xuartps {
173 struct uart_port *port;
170 struct clk *refclk; 174 struct clk *refclk;
171 struct clk *aperclk; 175 struct clk *aperclk;
176 unsigned int baud;
177 struct notifier_block clk_rate_change_nb;
172}; 178};
179#define to_xuartps(_nb) container_of(_nb, struct xuartps, clk_rate_change_nb);
173 180
174/** 181/**
175 * xuartps_isr - Interrupt handler 182 * xuartps_isr - Interrupt handler
@@ -385,6 +392,7 @@ static unsigned int xuartps_set_baud_rate(struct uart_port *port,
385 u32 cd, bdiv; 392 u32 cd, bdiv;
386 u32 mreg; 393 u32 mreg;
387 int div8; 394 int div8;
395 struct xuartps *xuartps = port->private_data;
388 396
389 calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, 397 calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
390 &div8); 398 &div8);
@@ -398,10 +406,105 @@ static unsigned int xuartps_set_baud_rate(struct uart_port *port,
398 xuartps_writel(mreg, XUARTPS_MR_OFFSET); 406 xuartps_writel(mreg, XUARTPS_MR_OFFSET);
399 xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET); 407 xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET);
400 xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET); 408 xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET);
409 xuartps->baud = baud;
401 410
402 return calc_baud; 411 return calc_baud;
403} 412}
404 413
414/**
415 * xuartps_clk_notitifer_cb - Clock notifier callback
416 * @nb: Notifier block
417 * @event: Notify event
418 * @data: Notifier data
419 * Returns NOTIFY_OK on success, NOTIFY_BAD on error.
420 */
421static int xuartps_clk_notifier_cb(struct notifier_block *nb,
422 unsigned long event, void *data)
423{
424 u32 ctrl_reg;
425 struct uart_port *port;
426 int locked = 0;
427 struct clk_notifier_data *ndata = data;
428 unsigned long flags = 0;
429 struct xuartps *xuartps = to_xuartps(nb);
430
431 port = xuartps->port;
432 if (port->suspended)
433 return NOTIFY_OK;
434
435 switch (event) {
436 case PRE_RATE_CHANGE:
437 {
438 u32 bdiv;
439 u32 cd;
440 int div8;
441
442 /*
443 * Find out if current baud-rate can be achieved with new clock
444 * frequency.
445 */
446 if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud,
447 &bdiv, &cd, &div8))
448 return NOTIFY_BAD;
449
450 spin_lock_irqsave(&xuartps->port->lock, flags);
451
452 /* Disable the TX and RX to set baud rate */
453 xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
454 (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS),
455 XUARTPS_CR_OFFSET);
456
457 spin_unlock_irqrestore(&xuartps->port->lock, flags);
458
459 return NOTIFY_OK;
460 }
461 case POST_RATE_CHANGE:
462 /*
463 * Set clk dividers to generate correct baud with new clock
464 * frequency.
465 */
466
467 spin_lock_irqsave(&xuartps->port->lock, flags);
468
469 locked = 1;
470 port->uartclk = ndata->new_rate;
471
472 xuartps->baud = xuartps_set_baud_rate(xuartps->port,
473 xuartps->baud);
474 /* fall through */
475 case ABORT_RATE_CHANGE:
476 if (!locked)
477 spin_lock_irqsave(&xuartps->port->lock, flags);
478
479 /* Set TX/RX Reset */
480 xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) |
481 (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST),
482 XUARTPS_CR_OFFSET);
483
484 while (xuartps_readl(XUARTPS_CR_OFFSET) &
485 (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST))
486 cpu_relax();
487
488 /*
489 * Clear the RX disable and TX disable bits and then set the TX
490 * enable bit and RX enable bit to enable the transmitter and
491 * receiver.
492 */
493 xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET);
494 ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET);
495 xuartps_writel(
496 (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) |
497 (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN),
498 XUARTPS_CR_OFFSET);
499
500 spin_unlock_irqrestore(&xuartps->port->lock, flags);
501
502 return NOTIFY_OK;
503 default:
504 return NOTIFY_DONE;
505 }
506}
507
405/*----------------------Uart Operations---------------------------*/ 508/*----------------------Uart Operations---------------------------*/
406 509
407/** 510/**
@@ -1164,13 +1267,19 @@ static int xuartps_probe(struct platform_device *pdev)
1164 goto err_out_clk_disable; 1267 goto err_out_clk_disable;
1165 } 1268 }
1166 1269
1270 xuartps_data->clk_rate_change_nb.notifier_call =
1271 xuartps_clk_notifier_cb;
1272 if (clk_notifier_register(xuartps_data->refclk,
1273 &xuartps_data->clk_rate_change_nb))
1274 dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
1275
1167 /* Initialize the port structure */ 1276 /* Initialize the port structure */
1168 port = xuartps_get_port(); 1277 port = xuartps_get_port();
1169 1278
1170 if (!port) { 1279 if (!port) {
1171 dev_err(&pdev->dev, "Cannot get uart_port structure\n"); 1280 dev_err(&pdev->dev, "Cannot get uart_port structure\n");
1172 rc = -ENODEV; 1281 rc = -ENODEV;
1173 goto err_out_clk_disable; 1282 goto err_out_notif_unreg;
1174 } else { 1283 } else {
1175 /* Register the port. 1284 /* Register the port.
1176 * This function also registers this device with the tty layer 1285 * This function also registers this device with the tty layer
@@ -1181,16 +1290,20 @@ static int xuartps_probe(struct platform_device *pdev)
1181 port->dev = &pdev->dev; 1290 port->dev = &pdev->dev;
1182 port->uartclk = clk_get_rate(xuartps_data->refclk); 1291 port->uartclk = clk_get_rate(xuartps_data->refclk);
1183 port->private_data = xuartps_data; 1292 port->private_data = xuartps_data;
1293 xuartps_data->port = port;
1184 platform_set_drvdata(pdev, port); 1294 platform_set_drvdata(pdev, port);
1185 rc = uart_add_one_port(&xuartps_uart_driver, port); 1295 rc = uart_add_one_port(&xuartps_uart_driver, port);
1186 if (rc) { 1296 if (rc) {
1187 dev_err(&pdev->dev, 1297 dev_err(&pdev->dev,
1188 "uart_add_one_port() failed; err=%i\n", rc); 1298 "uart_add_one_port() failed; err=%i\n", rc);
1189 goto err_out_clk_disable; 1299 goto err_out_notif_unreg;
1190 } 1300 }
1191 return 0; 1301 return 0;
1192 } 1302 }
1193 1303
1304err_out_notif_unreg:
1305 clk_notifier_unregister(xuartps_data->refclk,
1306 &xuartps_data->clk_rate_change_nb);
1194err_out_clk_disable: 1307err_out_clk_disable:
1195 clk_disable_unprepare(xuartps_data->refclk); 1308 clk_disable_unprepare(xuartps_data->refclk);
1196err_out_clk_dis_aper: 1309err_out_clk_dis_aper:
@@ -1212,6 +1325,8 @@ static int xuartps_remove(struct platform_device *pdev)
1212 int rc; 1325 int rc;
1213 1326
1214 /* Remove the xuartps port from the serial core */ 1327 /* Remove the xuartps port from the serial core */
1328 clk_notifier_unregister(xuartps_data->refclk,
1329 &xuartps_data->clk_rate_change_nb);
1215 rc = uart_remove_one_port(&xuartps_uart_driver, port); 1330 rc = uart_remove_one_port(&xuartps_uart_driver, port);
1216 port->mapbase = 0; 1331 port->mapbase = 0;
1217 clk_disable_unprepare(xuartps_data->refclk); 1332 clk_disable_unprepare(xuartps_data->refclk);