[ARM] CPUFREQ: S3C24XX serial CPU frequency scaling support.
Add support for CPU frequency scalling to the S3C24XX serial driver. Signed-off-by: Ben Dooks <ben-linux@fluff.org>
This commit is contained in:
Родитель
e24b864ab3
Коммит
3055547680
|
@ -42,6 +42,7 @@
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/cpufreq.h>
|
||||||
|
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
||||||
|
@ -452,6 +453,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
|
||||||
{
|
{
|
||||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||||
|
|
||||||
|
ourport->pm_level = level;
|
||||||
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 3:
|
case 3:
|
||||||
if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
|
if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
|
||||||
|
@ -661,6 +664,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
||||||
|
|
||||||
ourport->clksrc = clksrc;
|
ourport->clksrc = clksrc;
|
||||||
ourport->baudclk = clk;
|
ourport->baudclk = clk;
|
||||||
|
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (termios->c_cflag & CSIZE) {
|
switch (termios->c_cflag & CSIZE) {
|
||||||
|
@ -890,6 +894,93 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
|
||||||
return (info->reset_port)(port, cfg);
|
return (info->reset_port)(port, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_FREQ
|
||||||
|
|
||||||
|
static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
|
||||||
|
unsigned long val, void *data)
|
||||||
|
{
|
||||||
|
struct s3c24xx_uart_port *port;
|
||||||
|
struct uart_port *uport;
|
||||||
|
|
||||||
|
port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
|
||||||
|
uport = &port->port;
|
||||||
|
|
||||||
|
/* check to see if port is enabled */
|
||||||
|
|
||||||
|
if (port->pm_level != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* try and work out if the baudrate is changing, we can detect
|
||||||
|
* a change in rate, but we do not have support for detecting
|
||||||
|
* a disturbance in the clock-rate over the change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (IS_ERR(port->clk))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (port->baudclk_rate == clk_get_rate(port->clk))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (val == CPUFREQ_PRECHANGE) {
|
||||||
|
/* we should really shut the port down whilst the
|
||||||
|
* frequency change is in progress. */
|
||||||
|
|
||||||
|
} else if (val == CPUFREQ_POSTCHANGE) {
|
||||||
|
struct ktermios *termios;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
|
||||||
|
if (uport->info == NULL) {
|
||||||
|
printk(KERN_WARNING "%s: info NULL\n", __func__);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
tty = uport->info->port.tty;
|
||||||
|
|
||||||
|
if (tty == NULL) {
|
||||||
|
printk(KERN_WARNING "%s: tty is NULL\n", __func__);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
termios = tty->termios;
|
||||||
|
|
||||||
|
if (termios == NULL) {
|
||||||
|
printk(KERN_WARNING "%s: no termios?\n", __func__);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
s3c24xx_serial_set_termios(uport, termios, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||||
|
{
|
||||||
|
port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
|
||||||
|
|
||||||
|
return cpufreq_register_notifier(&port->freq_transition,
|
||||||
|
CPUFREQ_TRANSITION_NOTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||||
|
{
|
||||||
|
cpufreq_unregister_notifier(&port->freq_transition,
|
||||||
|
CPUFREQ_TRANSITION_NOTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* s3c24xx_serial_init_port
|
/* s3c24xx_serial_init_port
|
||||||
*
|
*
|
||||||
* initialise a single serial port from the platform device given
|
* initialise a single serial port from the platform device given
|
||||||
|
@ -1002,6 +1093,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
|
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
|
||||||
|
|
||||||
|
ret = s3c24xx_serial_cpufreq_register(ourport);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
probe_err:
|
probe_err:
|
||||||
|
@ -1015,6 +1110,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
|
||||||
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
|
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
|
||||||
|
|
||||||
if (port) {
|
if (port) {
|
||||||
|
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
||||||
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
||||||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,18 @@ struct s3c24xx_uart_info {
|
||||||
struct s3c24xx_uart_port {
|
struct s3c24xx_uart_port {
|
||||||
unsigned char rx_claimed;
|
unsigned char rx_claimed;
|
||||||
unsigned char tx_claimed;
|
unsigned char tx_claimed;
|
||||||
|
unsigned int pm_level;
|
||||||
|
unsigned long baudclk_rate;
|
||||||
|
|
||||||
struct s3c24xx_uart_info *info;
|
struct s3c24xx_uart_info *info;
|
||||||
struct s3c24xx_uart_clksrc *clksrc;
|
struct s3c24xx_uart_clksrc *clksrc;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct clk *baudclk;
|
struct clk *baudclk;
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_FREQ
|
||||||
|
struct notifier_block freq_transition;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* conversion functions */
|
/* conversion functions */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче