linux/drivers/media/i2c/smiapp-pll.c
<<
>>
Prefs
   1/*
   2 * drivers/media/i2c/smiapp-pll.c
   3 *
   4 * Generic driver for SMIA/SMIA++ compliant camera modules
   5 *
   6 * Copyright (C) 2011--2012 Nokia Corporation
   7 * Contact: Sakari Ailus <sakari.ailus@iki.fi>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License
  11 * version 2 as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful, but
  14 * WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 * General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21 * 02110-1301 USA
  22 *
  23 */
  24
  25#include <linux/gcd.h>
  26#include <linux/lcm.h>
  27#include <linux/module.h>
  28
  29#include "smiapp-pll.h"
  30
  31/* Return an even number or one. */
  32static inline uint32_t clk_div_even(uint32_t a)
  33{
  34        return max_t(uint32_t, 1, a & ~1);
  35}
  36
  37/* Return an even number or one. */
  38static inline uint32_t clk_div_even_up(uint32_t a)
  39{
  40        if (a == 1)
  41                return 1;
  42        return (a + 1) & ~1;
  43}
  44
  45static inline uint32_t is_one_or_even(uint32_t a)
  46{
  47        if (a == 1)
  48                return 1;
  49        if (a & 1)
  50                return 0;
  51
  52        return 1;
  53}
  54
  55static int bounds_check(struct device *dev, uint32_t val,
  56                        uint32_t min, uint32_t max, char *str)
  57{
  58        if (val >= min && val <= max)
  59                return 0;
  60
  61        dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
  62
  63        return -EINVAL;
  64}
  65
  66static void print_pll(struct device *dev, struct smiapp_pll *pll)
  67{
  68        dev_dbg(dev, "pre_pll_clk_div\t%d\n",  pll->pre_pll_clk_div);
  69        dev_dbg(dev, "pll_multiplier \t%d\n",  pll->pll_multiplier);
  70        if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
  71                dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
  72                dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
  73        }
  74        dev_dbg(dev, "vt_sys_clk_div \t%d\n",  pll->vt_sys_clk_div);
  75        dev_dbg(dev, "vt_pix_clk_div \t%d\n",  pll->vt_pix_clk_div);
  76
  77        dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
  78        dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
  79        dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
  80        if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
  81                dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
  82                        pll->op_sys_clk_freq_hz);
  83                dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
  84                        pll->op_pix_clk_freq_hz);
  85        }
  86        dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
  87        dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
  88}
  89
  90static int __smiapp_pll_calculate(struct device *dev,
  91                                  const struct smiapp_pll_limits *limits,
  92                                  struct smiapp_pll *pll, uint32_t mul,
  93                                  uint32_t div, uint32_t lane_op_clock_ratio)
  94{
  95        uint32_t sys_div;
  96        uint32_t best_pix_div = INT_MAX >> 1;
  97        uint32_t vt_op_binning_div;
  98        uint32_t more_mul_min, more_mul_max;
  99        uint32_t more_mul_factor;
 100        uint32_t min_vt_div, max_vt_div, vt_div;
 101        uint32_t min_sys_div, max_sys_div;
 102        unsigned int i;
 103        int rval;
 104
 105        /*
 106         * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
 107         * too high.
 108         */
 109        dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
 110
 111        /* Don't go above max pll multiplier. */
 112        more_mul_max = limits->max_pll_multiplier / mul;
 113        dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
 114                more_mul_max);
 115        /* Don't go above max pll op frequency. */
 116        more_mul_max =
 117                min_t(uint32_t,
 118                      more_mul_max,
 119                      limits->max_pll_op_freq_hz
 120                      / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
 121        dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
 122                more_mul_max);
 123        /* Don't go above the division capability of op sys clock divider. */
 124        more_mul_max = min(more_mul_max,
 125                           limits->op.max_sys_clk_div * pll->pre_pll_clk_div
 126                           / div);
 127        dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
 128                more_mul_max);
 129        /* Ensure we won't go above min_pll_multiplier. */
 130        more_mul_max = min(more_mul_max,
 131                           DIV_ROUND_UP(limits->max_pll_multiplier, mul));
 132        dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
 133                more_mul_max);
 134
 135        /* Ensure we won't go below min_pll_op_freq_hz. */
 136        more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
 137                                    pll->ext_clk_freq_hz / pll->pre_pll_clk_div
 138                                    * mul);
 139        dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
 140                more_mul_min);
 141        /* Ensure we won't go below min_pll_multiplier. */
 142        more_mul_min = max(more_mul_min,
 143                           DIV_ROUND_UP(limits->min_pll_multiplier, mul));
 144        dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
 145                more_mul_min);
 146
 147        if (more_mul_min > more_mul_max) {
 148                dev_dbg(dev,
 149                        "unable to compute more_mul_min and more_mul_max\n");
 150                return -EINVAL;
 151        }
 152
 153        more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
 154        dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
 155        more_mul_factor = lcm(more_mul_factor, limits->op.min_sys_clk_div);
 156        dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
 157                more_mul_factor);
 158        i = roundup(more_mul_min, more_mul_factor);
 159        if (!is_one_or_even(i))
 160                i <<= 1;
 161
 162        dev_dbg(dev, "final more_mul: %d\n", i);
 163        if (i > more_mul_max) {
 164                dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max);
 165                return -EINVAL;
 166        }
 167
 168        pll->pll_multiplier = mul * i;
 169        pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
 170        dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
 171
 172        pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
 173                / pll->pre_pll_clk_div;
 174
 175        pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
 176                * pll->pll_multiplier;
 177
 178        /* Derive pll_op_clk_freq_hz. */
 179        pll->op_sys_clk_freq_hz =
 180                pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
 181
 182        pll->op_pix_clk_div = pll->bits_per_pixel;
 183        dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
 184
 185        pll->op_pix_clk_freq_hz =
 186                pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
 187
 188        /*
 189         * Some sensors perform analogue binning and some do this
 190         * digitally. The ones doing this digitally can be roughly be
 191         * found out using this formula. The ones doing this digitally
 192         * should run at higher clock rate, so smaller divisor is used
 193         * on video timing side.
 194         */
 195        if (limits->min_line_length_pck_bin > limits->min_line_length_pck
 196            / pll->binning_horizontal)
 197                vt_op_binning_div = pll->binning_horizontal;
 198        else
 199                vt_op_binning_div = 1;
 200        dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
 201
 202        /*
 203         * Profile 2 supports vt_pix_clk_div E [4, 10]
 204         *
 205         * Horizontal binning can be used as a base for difference in
 206         * divisors. One must make sure that horizontal blanking is
 207         * enough to accommodate the CSI-2 sync codes.
 208         *
 209         * Take scaling factor into account as well.
 210         *
 211         * Find absolute limits for the factor of vt divider.
 212         */
 213        dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
 214        min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
 215                                  * pll->scale_n,
 216                                  lane_op_clock_ratio * vt_op_binning_div
 217                                  * pll->scale_m);
 218
 219        /* Find smallest and biggest allowed vt divisor. */
 220        dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
 221        min_vt_div = max(min_vt_div,
 222                         DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
 223                                      limits->vt.max_pix_clk_freq_hz));
 224        dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
 225                min_vt_div);
 226        min_vt_div = max_t(uint32_t, min_vt_div,
 227                           limits->vt.min_pix_clk_div
 228                           * limits->vt.min_sys_clk_div);
 229        dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
 230
 231        max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div;
 232        dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
 233        max_vt_div = min(max_vt_div,
 234                         DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
 235                                      limits->vt.min_pix_clk_freq_hz));
 236        dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
 237                max_vt_div);
 238
 239        /*
 240         * Find limitsits for sys_clk_div. Not all values are possible
 241         * with all values of pix_clk_div.
 242         */
 243        min_sys_div = limits->vt.min_sys_clk_div;
 244        dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
 245        min_sys_div = max(min_sys_div,
 246                          DIV_ROUND_UP(min_vt_div,
 247                                       limits->vt.max_pix_clk_div));
 248        dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
 249        min_sys_div = max(min_sys_div,
 250                          pll->pll_op_clk_freq_hz
 251                          / limits->vt.max_sys_clk_freq_hz);
 252        dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
 253        min_sys_div = clk_div_even_up(min_sys_div);
 254        dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
 255
 256        max_sys_div = limits->vt.max_sys_clk_div;
 257        dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
 258        max_sys_div = min(max_sys_div,
 259                          DIV_ROUND_UP(max_vt_div,
 260                                       limits->vt.min_pix_clk_div));
 261        dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
 262        max_sys_div = min(max_sys_div,
 263                          DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
 264                                       limits->vt.min_pix_clk_freq_hz));
 265        dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
 266
 267        /*
 268         * Find pix_div such that a legal pix_div * sys_div results
 269         * into a value which is not smaller than div, the desired
 270         * divisor.
 271         */
 272        for (vt_div = min_vt_div; vt_div <= max_vt_div;
 273             vt_div += 2 - (vt_div & 1)) {
 274                for (sys_div = min_sys_div;
 275                     sys_div <= max_sys_div;
 276                     sys_div += 2 - (sys_div & 1)) {
 277                        uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div);
 278
 279                        if (pix_div < limits->vt.min_pix_clk_div
 280                            || pix_div > limits->vt.max_pix_clk_div) {
 281                                dev_dbg(dev,
 282                                        "pix_div %d too small or too big (%d--%d)\n",
 283                                        pix_div,
 284                                        limits->vt.min_pix_clk_div,
 285                                        limits->vt.max_pix_clk_div);
 286                                continue;
 287                        }
 288
 289                        /* Check if this one is better. */
 290                        if (pix_div * sys_div
 291                            <= roundup(min_vt_div, best_pix_div))
 292                                best_pix_div = pix_div;
 293                }
 294                if (best_pix_div < INT_MAX >> 1)
 295                        break;
 296        }
 297
 298        pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
 299        pll->vt_pix_clk_div = best_pix_div;
 300
 301        pll->vt_sys_clk_freq_hz =
 302                pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
 303        pll->vt_pix_clk_freq_hz =
 304                pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
 305
 306        pll->pixel_rate_csi =
 307                pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
 308
 309        rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
 310                            limits->min_pll_ip_freq_hz,
 311                            limits->max_pll_ip_freq_hz,
 312                            "pll_ip_clk_freq_hz");
 313        if (!rval)
 314                rval = bounds_check(
 315                        dev, pll->pll_multiplier,
 316                        limits->min_pll_multiplier, limits->max_pll_multiplier,
 317                        "pll_multiplier");
 318        if (!rval)
 319                rval = bounds_check(
 320                        dev, pll->pll_op_clk_freq_hz,
 321                        limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
 322                        "pll_op_clk_freq_hz");
 323        if (!rval)
 324                rval = bounds_check(
 325                        dev, pll->op_sys_clk_div,
 326                        limits->op.min_sys_clk_div, limits->op.max_sys_clk_div,
 327                        "op_sys_clk_div");
 328        if (!rval)
 329                rval = bounds_check(
 330                        dev, pll->op_pix_clk_div,
 331                        limits->op.min_pix_clk_div, limits->op.max_pix_clk_div,
 332                        "op_pix_clk_div");
 333        if (!rval)
 334                rval = bounds_check(
 335                        dev, pll->op_sys_clk_freq_hz,
 336                        limits->op.min_sys_clk_freq_hz,
 337                        limits->op.max_sys_clk_freq_hz,
 338                        "op_sys_clk_freq_hz");
 339        if (!rval)
 340                rval = bounds_check(
 341                        dev, pll->op_pix_clk_freq_hz,
 342                        limits->op.min_pix_clk_freq_hz,
 343                        limits->op.max_pix_clk_freq_hz,
 344                        "op_pix_clk_freq_hz");
 345        if (!rval)
 346                rval = bounds_check(
 347                        dev, pll->vt_sys_clk_freq_hz,
 348                        limits->vt.min_sys_clk_freq_hz,
 349                        limits->vt.max_sys_clk_freq_hz,
 350                        "vt_sys_clk_freq_hz");
 351        if (!rval)
 352                rval = bounds_check(
 353                        dev, pll->vt_pix_clk_freq_hz,
 354                        limits->vt.min_pix_clk_freq_hz,
 355                        limits->vt.max_pix_clk_freq_hz,
 356                        "vt_pix_clk_freq_hz");
 357
 358        return rval;
 359}
 360
 361int smiapp_pll_calculate(struct device *dev,
 362                         const struct smiapp_pll_limits *limits,
 363                         struct smiapp_pll *pll)
 364{
 365        uint16_t min_pre_pll_clk_div;
 366        uint16_t max_pre_pll_clk_div;
 367        uint32_t lane_op_clock_ratio;
 368        uint32_t mul, div;
 369        unsigned int i;
 370        int rval = -EINVAL;
 371
 372        if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
 373                lane_op_clock_ratio = pll->csi2.lanes;
 374        else
 375                lane_op_clock_ratio = 1;
 376        dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
 377
 378        dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
 379                pll->binning_vertical);
 380
 381        switch (pll->bus_type) {
 382        case SMIAPP_PLL_BUS_TYPE_CSI2:
 383                /* CSI transfers 2 bits per clock per lane; thus times 2 */
 384                pll->pll_op_clk_freq_hz = pll->link_freq * 2
 385                        * (pll->csi2.lanes / lane_op_clock_ratio);
 386                break;
 387        case SMIAPP_PLL_BUS_TYPE_PARALLEL:
 388                pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel
 389                        / DIV_ROUND_UP(pll->bits_per_pixel,
 390                                       pll->parallel.bus_width);
 391                break;
 392        default:
 393                return -EINVAL;
 394        }
 395
 396        /* Figure out limits for pre-pll divider based on extclk */
 397        dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
 398                limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
 399        max_pre_pll_clk_div =
 400                min_t(uint16_t, limits->max_pre_pll_clk_div,
 401                      clk_div_even(pll->ext_clk_freq_hz /
 402                                   limits->min_pll_ip_freq_hz));
 403        min_pre_pll_clk_div =
 404                max_t(uint16_t, limits->min_pre_pll_clk_div,
 405                      clk_div_even_up(
 406                              DIV_ROUND_UP(pll->ext_clk_freq_hz,
 407                                           limits->max_pll_ip_freq_hz)));
 408        dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
 409                min_pre_pll_clk_div, max_pre_pll_clk_div);
 410
 411        i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
 412        mul = div_u64(pll->pll_op_clk_freq_hz, i);
 413        div = pll->ext_clk_freq_hz / i;
 414        dev_dbg(dev, "mul %d / div %d\n", mul, div);
 415
 416        min_pre_pll_clk_div =
 417                max_t(uint16_t, min_pre_pll_clk_div,
 418                      clk_div_even_up(
 419                              DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
 420                                           limits->max_pll_op_freq_hz)));
 421        dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
 422                min_pre_pll_clk_div, max_pre_pll_clk_div);
 423
 424        for (pll->pre_pll_clk_div = min_pre_pll_clk_div;
 425             pll->pre_pll_clk_div <= max_pre_pll_clk_div;
 426             pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
 427                rval = __smiapp_pll_calculate(dev, limits, pll, mul, div,
 428                                              lane_op_clock_ratio);
 429                if (rval)
 430                        continue;
 431
 432                print_pll(dev, pll);
 433                return 0;
 434        }
 435
 436        dev_info(dev, "unable to compute pre_pll divisor\n");
 437        return rval;
 438}
 439EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
 440
 441MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>");
 442MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
 443MODULE_LICENSE("GPL");
 444