linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 RESEND] serial: 8250: Add cpufreq support
@ 2012-05-15 15:10 Shankarmurthy, Akshay
  0 siblings, 0 replies; only message in thread
From: Shankarmurthy, Akshay @ 2012-05-15 15:10 UTC (permalink / raw)
  To: linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	swarren-DDmLM1+adcrQT0dZR+AlfA,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dianders-F7+t8E8rja9g9hUCZPvPmw,
	paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ,
	jamie-wmLquQDDieKakBO8gow8eQ,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w,
	alan-VuQAYsv1563Yd54FQh9/CA

This patch adds cpufreq support for 8250 serial driver. A clk structure
member has been added to the platform and port data structures. This
member is used by the cpufreq notifier callback to get the updated
clock rate. Also adds a member 'enable_cpufreq' to the plat_serial8250_port
and uart_port structures which decides the requirement of cpufreq registration
for each individual ports. If the port requires registration then
'enable_cpufreq' should be passed as TRUE from the board file.

Tested on TI DA850/OMAP-L138 EVM.

Signed-off-by: Chaithrika U S <chaithrika-l0cyMroinI0@public.gmane.org>
Signed-off-by: Shankarmurthy, Akshay <akshay.s-l0cyMroinI0@public.gmane.org>
---
v2 includes following changes :

1. Used "tty_port_tty_get" API to get the tty struct instead of accesing it
directly from the uart_port structure.
2. Added a boolean member "enable_cpufreq" to the uart_port and
serial8250_port structures. This indicates the requirement of cpu freq
registration for each individual ports.
3. Renamed the function from "serial8250_cpufreq_deregister" to
"serial8250_cpufreq_unregister".

Changes are as per these discussions
http://www.mail-archive.com/davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org/msg22841.html

 drivers/tty/serial/8250/8250.c |   79 ++++++++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250.h |    4 ++
 include/linux/serial_8250.h    |    2 +
 include/linux/serial_core.h    |    1 +
 4 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 5c27f7e..83b5585 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -38,6 +38,8 @@
 #include <linux/nmi.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
 #ifdef CONFIG_SPARC
 #include <linux/sunserialcore.h>
 #endif
@@ -3005,6 +3007,70 @@ void serial8250_resume_port(int line)
 	uart_resume_port(&serial8250_reg, port);
 }
 
+#ifdef CONFIG_CPU_FREQ
+static int serial8250_cpufreq_transition(struct notifier_block *nb,
+					     unsigned long val, void *data)
+{
+	struct uart_8250_port *p;
+	struct uart_port *uport;
+
+	p = container_of(nb, struct uart_8250_port, freq_transition);
+	uport = &p->port;
+
+	if (IS_ERR(p->clk))
+		goto cpu_freq_exit;
+
+	if (p->port.uartclk == clk_get_rate(p->clk))
+		goto cpu_freq_exit;
+
+	p->port.uartclk = clk_get_rate(p->clk);
+	if (val == CPUFREQ_POSTCHANGE) {
+		struct ktermios *termios;
+		struct tty_struct *tty;
+		if (uport->state == NULL)
+			goto cpu_freq_exit;
+
+		tty = tty_port_tty_get(&uport->state->port);
+		if (tty == NULL)
+			goto cpu_freq_exit;
+
+		termios = tty->termios;
+		if (termios == NULL) {
+			printk(KERN_WARNING "%s: no termios?\n", __func__);
+			goto cpu_freq_exit;
+		}
+
+		serial8250_set_termios(uport, termios, NULL);
+	}
+
+cpu_freq_exit:
+	return 0;
+}
+
+static inline int serial8250_cpufreq_register(struct uart_8250_port *p)
+{
+	p->freq_transition.notifier_call = serial8250_cpufreq_transition;
+
+	return cpufreq_register_notifier(&p->freq_transition,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void serial8250_cpufreq_unregister(struct uart_8250_port *p)
+{
+	cpufreq_unregister_notifier(&p->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int serial8250_cpufreq_register(struct uart_8250_port *p)
+{
+	return 0;
+}
+
+static inline void serial8250_cpufreq_unregister(struct uart_8250_port *p)
+{
+}
+#endif
+
 /*
  * Register a set of serial devices attached to a platform device.  The
  * list is terminated with a zero flags entry, which means we expect
@@ -3041,6 +3107,10 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 		port.pm			= p->pm;
 		port.dev		= &dev->dev;
 		port.irqflags		|= irqflag;
+		port.enable_cpufreq	= p->enable_cpufreq;
+		if (p->clk)
+			serial8250_ports[i].clk = p->clk;
+
 		ret = serial8250_register_port(&port);
 		if (ret < 0) {
 			dev_err(&dev->dev, "unable to register port at index %d "
@@ -3217,6 +3287,13 @@ int serial8250_register_port(struct uart_port *port)
 		ret = uart_add_one_port(&serial8250_reg, &uart->port);
 		if (ret == 0)
 			ret = uart->port.line;
+
+		if (port->enable_cpufreq) {
+			ret = serial8250_cpufreq_register(uart);
+			if (ret < 0)
+				printk(KERN_ERR
+					"Failed to add cpufreq notifier\n");
+		}
 	}
 	mutex_unlock(&serial_mutex);
 
@@ -3236,6 +3313,8 @@ void serial8250_unregister_port(int line)
 	struct uart_8250_port *uart = &serial8250_ports[line];
 
 	mutex_lock(&serial_mutex);
+	if (uart->port.enable_cpufreq)
+		serial8250_cpufreq_unregister(uart);
 	uart_remove_one_port(&serial8250_reg, &uart->port);
 	if (serial8250_isa_devs) {
 		uart->port.flags &= ~UPF_BOOT_AUTOCONF;
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 2868a1d..77d5876 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -37,6 +37,10 @@ struct uart_8250_port {
 	unsigned char		lsr_saved_flags;
 #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
 	unsigned char		msr_saved_flags;
+	struct clk		*clk;
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	freq_transition;
+#endif
 };
 
 struct old_serial_port {
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 8f012f8..fa30b81 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -23,6 +23,8 @@ struct plat_serial8250_port {
 	resource_size_t	mapbase;	/* resource base */
 	unsigned int	irq;		/* interrupt number */
 	unsigned long	irqflags;	/* request_irq flags */
+	struct clk	*clk;
+	bool            enable_cpufreq; /* CPU freq status */
 	unsigned int	uartclk;	/* UART clock rate */
 	void            *private_data;
 	unsigned char	regshift;	/* register shift */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 2db407a..5db67a6 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -380,6 +380,7 @@ struct uart_port {
 	unsigned char		suspended;
 	unsigned char		irq_wake;
 	unsigned char		unused[2];
+	bool			enable_cpufreq;		/* CPU freq status */
 	void			*private_data;		/* generic platform data pointer */
 };
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2012-05-15 15:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-15 15:10 [PATCH v2 RESEND] serial: 8250: Add cpufreq support Shankarmurthy, Akshay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).