forked from Minki/linux
serial: sprd: Add power management for the Spreadtrum serial controller
This patch adds power management for the Spreadtrum serial controller. Signed-off-by: Lanqing Liu <lanqing.liu@unisoc.com> Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
984df54e43
commit
4007098f4c
@ -100,10 +100,12 @@
|
|||||||
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
|
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
|
||||||
#define SPRD_IMSR_BREAK_DETECT BIT(7)
|
#define SPRD_IMSR_BREAK_DETECT BIT(7)
|
||||||
#define SPRD_IMSR_TIMEOUT BIT(13)
|
#define SPRD_IMSR_TIMEOUT BIT(13)
|
||||||
|
#define SPRD_DEFAULT_SOURCE_CLK 26000000
|
||||||
|
|
||||||
struct sprd_uart_port {
|
struct sprd_uart_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
char name[16];
|
char name[16];
|
||||||
|
struct clk *clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
|
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
|
||||||
@ -491,6 +493,22 @@ static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sprd_pm(struct uart_port *port, unsigned int state,
|
||||||
|
unsigned int oldstate)
|
||||||
|
{
|
||||||
|
struct sprd_uart_port *sup =
|
||||||
|
container_of(port, struct sprd_uart_port, port);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case UART_PM_STATE_ON:
|
||||||
|
clk_prepare_enable(sup->clk);
|
||||||
|
break;
|
||||||
|
case UART_PM_STATE_OFF:
|
||||||
|
clk_disable_unprepare(sup->clk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct uart_ops serial_sprd_ops = {
|
static const struct uart_ops serial_sprd_ops = {
|
||||||
.tx_empty = sprd_tx_empty,
|
.tx_empty = sprd_tx_empty,
|
||||||
.get_mctrl = sprd_get_mctrl,
|
.get_mctrl = sprd_get_mctrl,
|
||||||
@ -507,6 +525,7 @@ static const struct uart_ops serial_sprd_ops = {
|
|||||||
.request_port = sprd_request_port,
|
.request_port = sprd_request_port,
|
||||||
.config_port = sprd_config_port,
|
.config_port = sprd_config_port,
|
||||||
.verify_port = sprd_verify_port,
|
.verify_port = sprd_verify_port,
|
||||||
|
.pm = sprd_pm,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
|
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
|
||||||
@ -671,11 +690,45 @@ static int sprd_remove(struct platform_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sprd_clk_init(struct uart_port *uport)
|
||||||
|
{
|
||||||
|
struct clk *clk_uart, *clk_parent;
|
||||||
|
struct sprd_uart_port *u = sprd_port[uport->line];
|
||||||
|
|
||||||
|
clk_uart = devm_clk_get(uport->dev, "uart");
|
||||||
|
if (IS_ERR(clk_uart)) {
|
||||||
|
dev_warn(uport->dev, "uart%d can't get uart clock\n",
|
||||||
|
uport->line);
|
||||||
|
clk_uart = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_parent = devm_clk_get(uport->dev, "source");
|
||||||
|
if (IS_ERR(clk_parent)) {
|
||||||
|
dev_warn(uport->dev, "uart%d can't get source clock\n",
|
||||||
|
uport->line);
|
||||||
|
clk_parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clk_uart || clk_set_parent(clk_uart, clk_parent))
|
||||||
|
uport->uartclk = SPRD_DEFAULT_SOURCE_CLK;
|
||||||
|
else
|
||||||
|
uport->uartclk = clk_get_rate(clk_uart);
|
||||||
|
|
||||||
|
u->clk = devm_clk_get(uport->dev, "enable");
|
||||||
|
if (IS_ERR(u->clk)) {
|
||||||
|
if (PTR_ERR(u->clk) != -EPROBE_DEFER)
|
||||||
|
dev_err(uport->dev, "uart%d can't get enable clock\n",
|
||||||
|
uport->line);
|
||||||
|
return PTR_ERR(u->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int sprd_probe(struct platform_device *pdev)
|
static int sprd_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct uart_port *up;
|
struct uart_port *up;
|
||||||
struct clk *clk;
|
|
||||||
int irq;
|
int irq;
|
||||||
int index;
|
int index;
|
||||||
int ret;
|
int ret;
|
||||||
@ -704,9 +757,9 @@ static int sprd_probe(struct platform_device *pdev)
|
|||||||
up->ops = &serial_sprd_ops;
|
up->ops = &serial_sprd_ops;
|
||||||
up->flags = UPF_BOOT_AUTOCONF;
|
up->flags = UPF_BOOT_AUTOCONF;
|
||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, NULL);
|
ret = sprd_clk_init(up);
|
||||||
if (!IS_ERR_OR_NULL(clk))
|
if (ret)
|
||||||
up->uartclk = clk_get_rate(clk);
|
return ret;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
up->membase = devm_ioremap_resource(&pdev->dev, res);
|
up->membase = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
Loading…
Reference in New Issue
Block a user