static irqreturn_t arizona_fll_clock_ok(int irq, void *data) { struct arizona_fll *fll = data; arizona_fll_dbg(fll, "clock OK\n"); complete(&fll->ok); return IRQ_HANDLED; }
static irqreturn_t arizona_fll_lock(int irq, void *data) { struct arizona_fll *fll = data; arizona_fll_dbg(fll, "Locked\n"); complete(&fll->lock); return IRQ_HANDLED; }
static int arizona_calc_fll(struct arizona_fll *fll, struct arizona_fll_cfg *cfg, unsigned int Fref, unsigned int Fout) { unsigned int target, div, gcd_fll; int i, ratio; arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); /* Fref must be <=13.5MHz */ div = 1; cfg->refdiv = 0; while ((Fref / div) > 13500000) { div *= 2; cfg->refdiv++; if (div > 8) { arizona_fll_err(fll, "Can't scale %dMHz in to <=13.5MHz\n", Fref); return -EINVAL; } } /* Apply the division for our remaining calculations */ Fref /= div; /* Fvco should be over the targt; don't check the upper bound */ div = 1; while (Fout * div < 90000000 * fll->vco_mult) { div++; if (div > 7) { arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", Fout); return -EINVAL; } } target = Fout * div / fll->vco_mult; cfg->outdiv = div; arizona_fll_dbg(fll, "Fvco=%dHz\n", target); /* Find an appropraite FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { cfg->fratio_ref = arizona_fratio_ref(fll->arizona, i); cfg->fratio_sync = arizona_fratio_sync(fll->arizona, i); ratio = fll_fratios[i].ratio; break; } } if (i == ARRAY_SIZE(fll_fratios)) { arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", Fref); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { cfg->gain = fll_gains[i].gain; break; } } if (i == ARRAY_SIZE(fll_gains)) { arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", Fref); return -EINVAL; } cfg->n = target / (ratio * Fref); if (target % (ratio * Fref)) { gcd_fll = gcd(target, ratio * Fref); arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); cfg->theta = (target - (cfg->n * ratio * Fref)) / gcd_fll; cfg->lambda = (ratio * Fref) / gcd_fll; } else { cfg->theta = 0; cfg->lambda = 0; } /* Round down to 16bit range with cost of accuracy lost. * Denominator must be bigger than numerator so we only * take care of it. */ while (cfg->lambda >= (1 << 16)) { cfg->theta >>= 1; cfg->lambda >>= 1; } arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO_REF=%x(%d) FRATIO_SYNC=%x(%d)\n", cfg->fratio_ref, cfg->fratio_ref, cfg->fratio_sync, cfg->fratio_sync); arizona_fll_dbg(fll, "OUTDIV=%x REFCLK_DIV=%x\n", cfg->outdiv, cfg->refdiv); arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain); return 0; }
static int arizona_calc_fll(struct arizona_fll *fll, struct arizona_fll_cfg *cfg, unsigned int Fref, unsigned int Fout) { unsigned int target, div, gcd_fll; int i, ratio; arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); /* Fref must be <=13.5MHz */ div = 1; cfg->refdiv = 0; while ((Fref / div) > 13500000) { div *= 2; cfg->refdiv++; if (div > 8) { arizona_fll_err(fll, "Can't scale %dMHz in to <=13.5MHz\n", Fref); return -EINVAL; } } /* Apply the division for our remaining calculations */ Fref /= div; /* Fvco should be over the targt; don't check the upper bound */ div = 1; while (Fout * div < 90000000 * fll->vco_mult) { div++; if (div > 7) { arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", Fout); return -EINVAL; } } target = Fout * div / fll->vco_mult; cfg->outdiv = div; arizona_fll_dbg(fll, "Fvco=%dHz\n", target); /* Find an appropraite FLL_FRATIO and factor it out of the target */ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { cfg->fratio = fll_fratios[i].fratio; ratio = fll_fratios[i].ratio; break; } } if (i == ARRAY_SIZE(fll_fratios)) { arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", Fref); return -EINVAL; } cfg->n = target / (ratio * Fref); if (target % Fref) { gcd_fll = gcd(target, ratio * Fref); arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); cfg->theta = (target - (cfg->n * ratio * Fref)) / gcd_fll; cfg->lambda = (ratio * Fref) / gcd_fll; } else { cfg->theta = 0; cfg->lambda = 0; } arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", cfg->n, cfg->theta, cfg->lambda); arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); return 0; }