diff options
author | Alexander Shiyan <shc_work@mail.ru> | 2014-02-10 18:18:31 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-13 17:34:47 (GMT) |
commit | d3a8a252e177cfaa2fb04120dd944104e4417bf5 (patch) | |
tree | 45e15948a0d521d7e2117c840adb173f4ef6d190 /drivers/tty/serial/max310x.c | |
parent | 27027a70e21f62d143da142d66e508e70fc311b7 (diff) | |
download | linux-d3a8a252e177cfaa2fb04120dd944104e4417bf5.tar.xz |
serial: max310x: Migrate to CLK API
This patch removes "frequency" parameter from MAX310X platform_data
and uses CLK API for getting clock. Clock type (XTAL/OSC) is
determined by clk name.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/max310x.c')
-rw-r--r-- | drivers/tty/serial/max310x.c | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9e147f3..310ee55 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/bitops.h> +#include <linux/clk.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/tty.h> @@ -291,6 +292,7 @@ struct max310x_port { struct max310x_devtype *devtype; struct regmap *regmap; struct mutex mutex; + struct clk *clk; struct max310x_pdata *pdata; int gpio_used; #ifdef CONFIG_GPIOLIB @@ -546,18 +548,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int max310x_set_ref_clk(struct max310x_port *s) +static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, + bool xtal) { unsigned int div, clksrc, pllcfg = 0; long besterr = -1; - unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; + unsigned long fdiv, fmul, bestfreq = freq; /* First, update error without PLL */ - max310x_update_best_err(s->pdata->frequency, &besterr); + max310x_update_best_err(freq, &besterr); /* Try all possible PLL dividers */ for (div = 1; (div <= 63) && besterr; div++) { - fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); + fdiv = DIV_ROUND_CLOSEST(freq, div); /* Try multiplier 6 */ fmul = fdiv * 6; @@ -590,10 +593,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) } /* Configure clock source */ - if (s->pdata->driver_flags & MAX310X_EXT_CLK) - clksrc = MAX310X_CLKSRC_EXTCLK_BIT; - else - clksrc = MAX310X_CLKSRC_CRYST_BIT; + clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT; /* Configure PLL */ if (pllcfg) { @@ -605,7 +605,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); /* Wait for crystal */ - if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK)) + if (pllcfg && xtal) msleep(10); return (int)bestfreq; @@ -1078,9 +1078,11 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, struct regmap *regmap, int irq) { - struct max310x_port *s; struct max310x_pdata *pdata = dev_get_platdata(dev); - int i, ret, uartclk; + int i, ret, fmin, fmax, freq, uartclk; + struct clk *clk_osc, *clk_xtal; + struct max310x_port *s; + bool xtal = false; if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -1098,14 +1100,35 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return -ENOMEM; } - /* Check input frequency */ - if ((pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) - goto err_freq; - /* Check frequency for quartz */ - if (!(pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) - goto err_freq; + clk_osc = devm_clk_get(dev, "osc"); + clk_xtal = devm_clk_get(dev, "xtal"); + if (!IS_ERR(clk_osc)) { + s->clk = clk_osc; + fmin = 500000; + fmax = 35000000; + } else if (!IS_ERR(clk_xtal)) { + s->clk = clk_xtal; + fmin = 1000000; + fmax = 4000000; + xtal = true; + } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || + PTR_ERR(clk_xtal) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else { + dev_err(dev, "Cannot get clock\n"); + return -EINVAL; + } + + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; + + freq = clk_get_rate(s->clk); + /* Check frequency limits */ + if (freq < fmin || freq > fmax) { + ret = -ERANGE; + goto out_clk; + } s->pdata = pdata; s->regmap = regmap; @@ -1117,7 +1140,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) - return ret; + goto out_clk; for (i = 0; i < devtype->nr; i++) { unsigned int offs = i << 5; @@ -1139,7 +1162,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_MODE1_AUTOSLEEP_BIT); } - uartclk = max310x_set_ref_clk(s); + uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); /* Register UART driver */ @@ -1151,7 +1174,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, ret = uart_register_driver(&s->uart); if (ret) { dev_err(dev, "Registering UART driver failed\n"); - return ret; + goto out_clk; } for (i = 0; i < devtype->nr; i++) { @@ -1208,19 +1231,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(dev), s); - if (ret) { - dev_err(dev, "Unable to reguest IRQ %i\n", irq); + if (!ret) + return 0; + + dev_err(dev, "Unable to reguest IRQ %i\n", irq); #ifdef CONFIG_GPIOLIB - if (s->gpio_used) - WARN_ON(gpiochip_remove(&s->gpio)); + if (s->gpio_used) + WARN_ON(gpiochip_remove(&s->gpio)); #endif - } - return ret; +out_clk: + clk_disable_unprepare(s->clk); -err_freq: - dev_err(dev, "Frequency parameter incorrect\n"); - return -EINVAL; + return ret; } static int max310x_remove(struct device *dev) @@ -1236,6 +1259,7 @@ static int max310x_remove(struct device *dev) } uart_unregister_driver(&s->uart); + clk_disable_unprepare(s->clk); #ifdef CONFIG_GPIOLIB if (s->gpio_used) |