/* * CIE lightness to PWM conversion. * * The CIE 1931 lightness formula is what actually describes how we perceive * light: * Y = (L* / 902.3) if L* ≤ 0.08856 * Y = ((L* + 16) / 116)^3 if L* > 0.08856 * * Where Y is the luminance, the amount of light coming out of the screen, and * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human * perceives the screen to be, and is a number between 0 and 100. * * The following function does the fixed point maths needed to implement the * above formula. */ static u64 cie1931(unsigned int lightness, unsigned int scale) { u64 retval; lightness *= 100; if (lightness <= (8 * scale)) { retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023); } else { retval = int_pow((lightness + (16 * scale)) / 116, 3); retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale)); } return retval; }
static int clk_audio_pll_compute_frac(unsigned long rate, unsigned long parent_rate, unsigned long *nd, unsigned long *fracr) { unsigned long long tmp; unsigned long long r; if (!rate) return -EINVAL; tmp = rate; r = do_div(tmp, parent_rate); if (tmp == 0 || (tmp - 1) > AUDIO_PLL_ND_MAX) return -EINVAL; *nd = tmp - 1; tmp = r * AUDIO_PLL_DIV_FRAC; tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate); if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK) return -EINVAL; /* we can cast here as we verified the bounds just above */ *fracr = (unsigned long)tmp; return 0; }
static void params_from_rate(unsigned long requested_rate, unsigned long parent_rate, unsigned int *sdm, unsigned int *n2, u8 flags) { uint64_t div = parent_rate; uint64_t frac = do_div(div, requested_rate); frac *= SDM_DEN; if (flags & CLK_MESON_MPLL_ROUND_CLOSEST) *sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate); else *sdm = DIV_ROUND_UP_ULL(frac, requested_rate); if (*sdm == SDM_DEN) { *sdm = 0; div += 1; } if (div < N2_MIN) { *n2 = N2_MIN; *sdm = 0; } else if (div > N2_MAX) { *n2 = N2_MAX; *sdm = SDM_DEN - 1; } else { *n2 = div; } }
static void update_fim_nominal(struct imx_media_fim *fim, const struct v4l2_fract *fi) { if (fi->denominator == 0) { dev_dbg(fim->sd->dev, "no frame interval, FIM disabled\n"); fim->enabled = false; return; } fim->nominal = DIV_ROUND_CLOSEST_ULL(1000000ULL * (u64)fi->numerator, fi->denominator); dev_dbg(fim->sd->dev, "FI=%lu usec\n", fim->nominal); }
/* * Create a default correction table for PWM values to create linear brightness * for LED based backlights using the CIE1931 algorithm. */ static int pwm_backlight_brightness_default(struct device *dev, struct platform_pwm_backlight_data *data, unsigned int period) { unsigned int counter = 0; unsigned int i, n; u64 retval; /* * Count the number of bits needed to represent the period number. The * number of bits is used to calculate the number of levels used for the * brightness-levels table, the purpose of this calculation is have a * pre-computed table with enough levels to get linear brightness * perception. The period is divided by the number of bits so for a * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM * we have 65535 / 16 = 4096 brightness levels. * * Note that this method is based on empirical testing on different * devices with PWM of 8 and 16 bits of resolution. */ n = period; while (n) { counter += n % 2; n >>= 1; } data->max_brightness = DIV_ROUND_UP(period, counter); data->levels = devm_kcalloc(dev, data->max_brightness, sizeof(*data->levels), GFP_KERNEL); if (!data->levels) return -ENOMEM; /* Fill the table using the cie1931 algorithm */ for (i = 0; i < data->max_brightness; i++) { retval = cie1931((i * PWM_LUMINANCE_SCALE) / data->max_brightness, PWM_LUMINANCE_SCALE) * period; retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE); if (retval > UINT_MAX) return -EINVAL; data->levels[i] = (unsigned int)retval; } data->dft_brightness = data->max_brightness / 2; data->max_brightness--; return 0; }
static unsigned long clk_audio_pll_fout(unsigned long parent_rate, unsigned long nd, unsigned long fracr) { unsigned long long fr = (unsigned long long)parent_rate * (unsigned long long)fracr; pr_debug("A PLL: %s, fr = %llu\n" , __func__ , fr); fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC); pr_debug("A PLL: %s, fr = %llu\n" , __func__ , fr); return parent_rate * (nd + 1) + fr; }
static void imx_ocotp_set_imx7_timing(struct ocotp_priv *priv) { unsigned long clk_rate = 0; u64 fsource, strobe_prog; u32 timing = 0; /* i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1 * 6.4.3.3 */ clk_rate = clk_get_rate(priv->clk); fsource = DIV_ROUND_UP_ULL((u64)clk_rate * DEF_FSOURCE, NSEC_PER_SEC) + 1; strobe_prog = DIV_ROUND_CLOSEST_ULL((u64)clk_rate * DEF_STROBE_PROG, NSEC_PER_SEC) + 1; timing = strobe_prog & 0x00000FFF; timing |= (fsource << 12) & 0x000FF000; writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING); }
/* pll_rate = pllin_rate * R * J.D / P * 1 <= R <= 16 * 1 <= J <= 63 * 0 <= D <= 9999 * 1 <= P <= 15 * 64 MHz <= pll_rate <= 100 MHz * if D == 0 * 1 MHz <= pllin_rate / P <= 20 MHz * else if D > 0 * 6.667 MHz <= pllin_rate / P <= 20 MHz * 4 <= J <= 11 * R = 1 */ static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai, unsigned long pllin_rate, unsigned long pll_rate) { struct device *dev = dai->dev; struct snd_soc_codec *codec = dai->codec; struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); unsigned long common; int R, J, D, P; unsigned long K; /* 10000 * J.D */ unsigned long num; unsigned long den; common = gcd(pll_rate, pllin_rate); dev_dbg(dev, "pll %lu pllin %lu common %lu\n", pll_rate, pllin_rate, common); num = pll_rate / common; den = pllin_rate / common; /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */ if (pllin_rate / den > 20000000 && num < 8) { num *= DIV_ROUND_UP(pllin_rate / den, 20000000); den *= DIV_ROUND_UP(pllin_rate / den, 20000000); } dev_dbg(dev, "num / den = %lu / %lu\n", num, den); P = den; if (den <= 15 && num <= 16 * 63 && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) { /* Try the case with D = 0 */ D = 0; /* factor 'num' into J and R, such that R <= 16 and J <= 63 */ for (R = 16; R; R--) { if (num % R) continue; J = num / R; if (J == 0 || J > 63) continue; dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P); pcm512x->real_pll = pll_rate; goto done; } /* no luck */ } R = 1; if (num > 0xffffffffUL / 10000) goto fallback; /* Try to find an exact pll_rate using the D > 0 case */ common = gcd(10000 * num, den); num = 10000 * num / common; den /= common; dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common); for (P = den; P <= 15; P++) { if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P) continue; if (num * P % den) continue; K = num * P / den; /* J == 12 is ok if D == 0 */ if (K < 40000 || K > 120000) continue; J = K / 10000; D = K % 10000; dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P); pcm512x->real_pll = pll_rate; goto done; } /* Fall back to an approximate pll_rate */ fallback: /* find smallest possible P */ P = DIV_ROUND_UP(pllin_rate, 20000000); if (!P) P = 1; else if (P > 15) { dev_err(dev, "Need a slower clock as pll-input\n"); return -EINVAL; } if (pllin_rate / P < 6667000) { dev_err(dev, "Need a faster clock as pll-input\n"); return -EINVAL; } K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate); if (K < 40000) K = 40000; /* J == 12 is ok if D == 0 */ if (K > 120000) K = 120000; J = K / 10000; D = K % 10000; dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P); pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P); done: pcm512x->pll_r = R; pcm512x->pll_j = J; pcm512x->pll_d = D; pcm512x->pll_p = P; return 0; }
/* Initialize the DLL (Programmable Delay Line) */ static int msm_init_cm_dll(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int wait_cnt = 50; unsigned long flags; u32 config; spin_lock_irqsave(&host->lock, flags); /* * Make sure that clock is always enabled when DLL * tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_CLK_PWRSAVE; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); if (msm_host->use_14lpp_dll_reset) { config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_CK_OUT_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config |= CORE_DLL_CLOCK_DISABLE; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_RST; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); msm_cm_dll_set_freq(host); if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk)) { u32 mclk_freq = 0; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= CORE_FLL_CYCLE_CNT; if (config) mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8), clk_get_rate(msm_host->xo_clk)); else mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4), clk_get_rate(msm_host->xo_clk)); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= ~(0xFF << 10); config |= mclk_freq << 10; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); /* wait for 5us before enabling DLL clock */ udelay(5); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_DLL_RST; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config &= ~CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); if (msm_host->use_14lpp_dll_reset) { msm_cm_dll_set_freq(host); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config &= ~CORE_DLL_CLOCK_DISABLE; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_DLL_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CK_OUT_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) & CORE_DLL_LOCK)) { /* max. wait for 50us sec for LOCK bit to be set */ if (--wait_cnt == 0) { dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n", mmc_hostname(mmc)); spin_unlock_irqrestore(&host->lock, flags); return -ETIMEDOUT; } udelay(1); } spin_unlock_irqrestore(&host->lock, flags); return 0; }
static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll, unsigned long rate, unsigned long parent_rate, bool update) { const struct clk_pll_characteristics *characteristics = pll->characteristics; unsigned long bestremainder = ULONG_MAX; unsigned long maxdiv, mindiv, tmpdiv; long bestrate = -ERANGE; unsigned long bestdiv = 0; unsigned long bestmul = 0; unsigned long bestfrac = 0; if (rate < characteristics->output[0].min || rate > characteristics->output[0].max) return -ERANGE; if (!pll->characteristics->upll) { mindiv = parent_rate / rate; if (mindiv < 2) mindiv = 2; maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate); if (maxdiv > PLL_DIV_MAX) maxdiv = PLL_DIV_MAX; } else { mindiv = maxdiv = UPLL_DIV; } for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { unsigned long remainder; unsigned long tmprate; unsigned long tmpmul; unsigned long tmpfrac = 0; /* * Calculate the multiplier associated with the current * divider that provide the closest rate to the requested one. */ tmpmul = mult_frac(rate, tmpdiv, parent_rate); tmprate = mult_frac(parent_rate, tmpmul, tmpdiv); remainder = rate - tmprate; if (remainder) { tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22), parent_rate); tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate, tmpdiv * (1 << 22)); if (tmprate > rate) remainder = tmprate - rate; else remainder = rate - tmprate; } /* * Compare the remainder with the best remainder found until * now and elect a new best multiplier/divider pair if the * current remainder is smaller than the best one. */ if (remainder < bestremainder) { bestremainder = remainder; bestdiv = tmpdiv; bestmul = tmpmul; bestrate = tmprate; bestfrac = tmpfrac; } /* We've found a perfect match! */ if (!remainder) break; } /* Check if bestrate is a valid output rate */ if (bestrate < characteristics->output[0].min && bestrate > characteristics->output[0].max) return -ERANGE; if (update) { pll->div = bestdiv - 1; pll->mul = bestmul - 1; pll->frac = bestfrac; } return bestrate; }
static u32 calc_residency(struct drm_i915_private *dev_priv, i915_reg_t reg) { return DIV_ROUND_CLOSEST_ULL(intel_rc6_residency_us(dev_priv, reg), 1000); }