]> Pileus Git - ~andy/linux/blobdiff - drivers/tty/serial/mpc52xx_uart.c
serial: mpc512x: cleanup clock API use
[~andy/linux] / drivers / tty / serial / mpc52xx_uart.c
index e1280a20b7a2f4c840e400039d79a40196ae7e5a..5be1df39f9f5f6b8fe0671bba23ba8f566e685f4 100644 (file)
@@ -107,6 +107,8 @@ struct psc_ops {
        unsigned int    (*set_baudrate)(struct uart_port *port,
                                        struct ktermios *new,
                                        struct ktermios *old);
+       int             (*clock_alloc)(struct uart_port *port);
+       void            (*clock_relse)(struct uart_port *port);
        int             (*clock)(struct uart_port *port, int enable);
        int             (*fifoc_init)(void);
        void            (*fifoc_uninit)(void);
@@ -616,31 +618,73 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
        return IRQ_NONE;
 }
 
-static int mpc512x_psc_clock(struct uart_port *port, int enable)
+static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
+
+/* called from within the .request_port() callback (allocation) */
+static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
-       struct clk *psc_clk;
        int psc_num;
-       char clk_name[10];
+       char clk_name[16];
+       struct clk *clk;
+       int err;
+
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+       clk = devm_clk_get(port->dev, clk_name);
+       if (IS_ERR(clk)) {
+               dev_err(port->dev, "Failed to get MCLK!\n");
+               return PTR_ERR(clk);
+       }
+       err = clk_prepare_enable(clk);
+       if (err) {
+               dev_err(port->dev, "Failed to enable MCLK!\n");
+               return err;
+       }
+       psc_mclk_clk[psc_num] = clk;
+       return 0;
+}
+
+/* called from within the .release_port() callback (release) */
+static void mpc512x_psc_relse_clock(struct uart_port *port)
+{
+       int psc_num;
+       struct clk *clk;
+
+       psc_num = (port->mapbase & 0xf00) >> 8;
+       clk = psc_mclk_clk[psc_num];
+       if (clk) {
+               clk_disable_unprepare(clk);
+               psc_mclk_clk[psc_num] = NULL;
+       }
+}
+
+/* implementation of the .clock() callback (enable/disable) */
+static int mpc512x_psc_endis_clock(struct uart_port *port, int enable)
+{
+       int psc_num;
+       struct clk *psc_clk;
+       int ret;
 
        if (uart_console(port))
                return 0;
 
        psc_num = (port->mapbase & 0xf00) >> 8;
-       snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-       psc_clk = clk_get(port->dev, clk_name);
-       if (IS_ERR(psc_clk)) {
+       psc_clk = psc_mclk_clk[psc_num];
+       if (!psc_clk) {
                dev_err(port->dev, "Failed to get PSC clock entry!\n");
                return -ENODEV;
        }
 
-       dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis");
-
-       if (enable)
-               clk_enable(psc_clk);
-       else
+       dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis");
+       if (enable) {
+               ret = clk_enable(psc_clk);
+               if (ret)
+                       dev_err(port->dev, "Failed to enable MCLK!\n");
+               return ret;
+       } else {
                clk_disable(psc_clk);
-
-       return 0;
+               return 0;
+       }
 }
 
 static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -873,7 +917,9 @@ static struct psc_ops mpc5125_psc_ops = {
        .cw_disable_ints = mpc5125_psc_cw_disable_ints,
        .cw_restore_ints = mpc5125_psc_cw_restore_ints,
        .set_baudrate = mpc5125_psc_set_baudrate,
-       .clock = mpc512x_psc_clock,
+       .clock_alloc = mpc512x_psc_alloc_clock,
+       .clock_relse = mpc512x_psc_relse_clock,
+       .clock = mpc512x_psc_endis_clock,
        .fifoc_init = mpc512x_psc_fifoc_init,
        .fifoc_uninit = mpc512x_psc_fifoc_uninit,
        .get_irq = mpc512x_psc_get_irq,
@@ -906,7 +952,9 @@ static struct psc_ops mpc512x_psc_ops = {
        .cw_disable_ints = mpc512x_psc_cw_disable_ints,
        .cw_restore_ints = mpc512x_psc_cw_restore_ints,
        .set_baudrate = mpc512x_psc_set_baudrate,
-       .clock = mpc512x_psc_clock,
+       .clock_alloc = mpc512x_psc_alloc_clock,
+       .clock_relse = mpc512x_psc_relse_clock,
+       .clock = mpc512x_psc_endis_clock,
        .fifoc_init = mpc512x_psc_fifoc_init,
        .fifoc_uninit = mpc512x_psc_fifoc_uninit,
        .get_irq = mpc512x_psc_get_irq,
@@ -1166,6 +1214,9 @@ mpc52xx_uart_type(struct uart_port *port)
 static void
 mpc52xx_uart_release_port(struct uart_port *port)
 {
+       if (psc_ops->clock_relse)
+               psc_ops->clock_relse(port);
+
        /* remapped by us ? */
        if (port->flags & UPF_IOREMAP) {
                iounmap(port->membase);
@@ -1190,11 +1241,24 @@ mpc52xx_uart_request_port(struct uart_port *port)
        err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
                        "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
 
-       if (err && (port->flags & UPF_IOREMAP)) {
+       if (err)
+               goto out_membase;
+
+       if (psc_ops->clock_alloc) {
+               err = psc_ops->clock_alloc(port);
+               if (err)
+                       goto out_mapregion;
+       }
+
+       return 0;
+
+out_mapregion:
+       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+out_membase:
+       if (port->flags & UPF_IOREMAP) {
                iounmap(port->membase);
                port->membase = NULL;
        }
-
        return err;
 }