aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/samsung.c96
-rw-r--r--drivers/serial/samsung.h6
2 files changed, 102 insertions, 0 deletions
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 1e219d3d0352..ebeda832c8a3 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -42,6 +42,7 @@
42#include <linux/serial.h> 42#include <linux/serial.h>
43#include <linux/delay.h> 43#include <linux/delay.h>
44#include <linux/clk.h> 44#include <linux/clk.h>
45#include <linux/cpufreq.h>
45 46
46#include <asm/irq.h> 47#include <asm/irq.h>
47 48
@@ -452,6 +453,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
452{ 453{
453 struct s3c24xx_uart_port *ourport = to_ourport(port); 454 struct s3c24xx_uart_port *ourport = to_ourport(port);
454 455
456 ourport->pm_level = level;
457
455 switch (level) { 458 switch (level) {
456 case 3: 459 case 3:
457 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) 460 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
@@ -661,6 +664,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
661 664
662 ourport->clksrc = clksrc; 665 ourport->clksrc = clksrc;
663 ourport->baudclk = clk; 666 ourport->baudclk = clk;
667 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
664 } 668 }
665 669
666 switch (termios->c_cflag & CSIZE) { 670 switch (termios->c_cflag & CSIZE) {
@@ -890,6 +894,93 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
890 return (info->reset_port)(port, cfg); 894 return (info->reset_port)(port, cfg);
891} 895}
892 896
897
898#ifdef CONFIG_CPU_FREQ
899
900static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
901 unsigned long val, void *data)
902{
903 struct s3c24xx_uart_port *port;
904 struct uart_port *uport;
905
906 port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
907 uport = &port->port;
908
909 /* check to see if port is enabled */
910
911 if (port->pm_level != 0)
912 return 0;
913
914 /* try and work out if the baudrate is changing, we can detect
915 * a change in rate, but we do not have support for detecting
916 * a disturbance in the clock-rate over the change.
917 */
918
919 if (IS_ERR(port->clk))
920 goto exit;
921
922 if (port->baudclk_rate == clk_get_rate(port->clk))
923 goto exit;
924
925 if (val == CPUFREQ_PRECHANGE) {
926 /* we should really shut the port down whilst the
927 * frequency change is in progress. */
928
929 } else if (val == CPUFREQ_POSTCHANGE) {
930 struct ktermios *termios;
931 struct tty_struct *tty;
932
933 if (uport->info == NULL) {
934 printk(KERN_WARNING "%s: info NULL\n", __func__);
935 goto exit;
936 }
937
938 tty = uport->info->port.tty;
939
940 if (tty == NULL) {
941 printk(KERN_WARNING "%s: tty is NULL\n", __func__);
942 goto exit;
943 }
944
945 termios = tty->termios;
946
947 if (termios == NULL) {
948 printk(KERN_WARNING "%s: no termios?\n", __func__);
949 goto exit;
950 }
951
952 s3c24xx_serial_set_termios(uport, termios, NULL);
953 }
954
955 exit:
956 return 0;
957}
958
959static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
960{
961 port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
962
963 return cpufreq_register_notifier(&port->freq_transition,
964 CPUFREQ_TRANSITION_NOTIFIER);
965}
966
967static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
968{
969 cpufreq_unregister_notifier(&port->freq_transition,
970 CPUFREQ_TRANSITION_NOTIFIER);
971}
972
973#else
974static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
975{
976 return 0;
977}
978
979static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
980{
981}
982#endif
983
893/* s3c24xx_serial_init_port 984/* s3c24xx_serial_init_port
894 * 985 *
895 * initialise a single serial port from the platform device given 986 * initialise a single serial port from the platform device given
@@ -1002,6 +1093,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
1002 if (ret < 0) 1093 if (ret < 0)
1003 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); 1094 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
1004 1095
1096 ret = s3c24xx_serial_cpufreq_register(ourport);
1097 if (ret < 0)
1098 dev_err(&dev->dev, "failed to add cpufreq notifier\n");
1099
1005 return 0; 1100 return 0;
1006 1101
1007 probe_err: 1102 probe_err:
@@ -1015,6 +1110,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
1015 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); 1110 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1016 1111
1017 if (port) { 1112 if (port) {
1113 s3c24xx_serial_cpufreq_deregister(to_ourport(port));
1018 device_remove_file(&dev->dev, &dev_attr_clock_source); 1114 device_remove_file(&dev->dev, &dev_attr_clock_source);
1019 uart_remove_one_port(&s3c24xx_uart_drv, port); 1115 uart_remove_one_port(&s3c24xx_uart_drv, port);
1020 } 1116 }
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index 5c92ebbe7d9e..be263423205d 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -33,12 +33,18 @@ struct s3c24xx_uart_info {
33struct s3c24xx_uart_port { 33struct s3c24xx_uart_port {
34 unsigned char rx_claimed; 34 unsigned char rx_claimed;
35 unsigned char tx_claimed; 35 unsigned char tx_claimed;
36 unsigned int pm_level;
37 unsigned long baudclk_rate;
36 38
37 struct s3c24xx_uart_info *info; 39 struct s3c24xx_uart_info *info;
38 struct s3c24xx_uart_clksrc *clksrc; 40 struct s3c24xx_uart_clksrc *clksrc;
39 struct clk *clk; 41 struct clk *clk;
40 struct clk *baudclk; 42 struct clk *baudclk;
41 struct uart_port port; 43 struct uart_port port;
44
45#ifdef CONFIG_CPU_FREQ
46 struct notifier_block freq_transition;
47#endif
42}; 48};
43 49
44/* conversion functions */ 50/* conversion functions */