static int __devinit device_gpadc_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
struct pm80x_subchip *subchip = chip->subchip;
struct regmap *map = subchip->regmap_gpadc;
int data = 0, mask = 0, ret = 0;
if (!map) {
dev_warn(chip->dev,
"Warning: gpadc regmap is not available!\n");
return -EINVAL;
}
/*
* initialize GPADC without activating it turn on GPADC
* measurments
*/
ret = regmap_update_bits(map,
PM800_GPADC_MISC_CONFIG2,
PM800_GPADC_MISC_GPFSM_EN,
PM800_GPADC_MISC_GPFSM_EN);
if (ret < 0)
goto out;
/*
* This function configures the ADC as requires for
* CP implementation.CP does not "own" the ADC configuration
* registers and relies on AP.
* Reason: enable automatic ADC measurements needed
* for CP to get VBAT and RF temperature readings.
*/
ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN1,
PM800_MEAS_EN1_VBAT, PM800_MEAS_EN1_VBAT);
if (ret < 0)
goto out;
ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN2,
(PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN),
(PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN));
if (ret < 0)
goto out;
/*
* the defult of PM800 is GPADC operates at 100Ks/s rate
* and Number of GPADC slots with active current bias prior
* to GPADC sampling = 1 slot for all GPADCs set for
* Temprature mesurmants
*/
mask = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
if (pdata && (pdata->batt_det == 0))
data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
else
data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN2 |
PM800_GPADC_GP_BIAS_EN3);
ret = regmap_update_bits(map, PM800_GP_BIAS_ENA1, mask, data);
if (ret < 0)
goto out;
dev_info(chip->dev, "pm800 device_gpadc_init: Done\n");
return 0;
out:
dev_info(chip->dev, "pm800 device_gpadc_init: Failed!\n");
return ret;
}
int arizona_set_fll(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout)
{
struct arizona *arizona = fll->arizona;
struct arizona_fll_cfg cfg, sync;
unsigned int reg, val;
int syncsrc;
bool ena;
int ret;
ret = regmap_read(arizona->regmap, fll->base + 1, ®);
if (ret != 0) {
arizona_fll_err(fll, "Failed to read current state: %d\n",
ret);
return ret;
}
ena = reg & ARIZONA_FLL1_ENA;
if (Fout) {
/* Do we have a 32kHz reference? */
regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
switch (val & ARIZONA_CLK_32K_SRC_MASK) {
case ARIZONA_CLK_SRC_MCLK1:
case ARIZONA_CLK_SRC_MCLK2:
syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
break;
default:
syncsrc = -1;
}
if (source == syncsrc)
syncsrc = -1;
if (syncsrc >= 0) {
ret = arizona_calc_fll(fll, &sync, Fref, Fout);
if (ret != 0)
return ret;
ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
if (ret != 0)
return ret;
} else {
ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
if (ret != 0)
return ret;
}
} else {
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, 0);
regmap_update_bits(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA, 0);
if (ena)
pm_runtime_put_autosuspend(arizona->dev);
return 0;
}
regmap_update_bits(arizona->regmap, fll->base + 5,
ARIZONA_FLL1_OUTDIV_MASK,
cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
if (syncsrc >= 0) {
arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
} else {
arizona_apply_fll(arizona, fll->base, &cfg, source);
}
if (!ena)
pm_runtime_get(arizona->dev);
/* Clear any pending completions */
try_wait_for_completion(&fll->ok);
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
if (syncsrc >= 0)
regmap_update_bits(arizona->regmap, fll->base + 0x11,
ARIZONA_FLL1_SYNC_ENA,
ARIZONA_FLL1_SYNC_ENA);
ret = wait_for_completion_timeout(&fll->ok,
msecs_to_jiffies(25));
if (ret == 0)
arizona_fll_warn(fll, "Timed out waiting for lock\n");
return 0;
}
开发者ID:LeeShuni,项目名称:linux,代码行数:89,代码来源:arizona.c
示例8: pm8xxx_read_channel_rsv
static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc,
const struct pm8xxx_chan_info *ch,
u8 rsv, u16 *adc_code,
bool force_ratiometric)
{
int ret;
unsigned int val;
u8 rsvmask, rsvval;
u8 lsb, msb;
dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n",
ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv);
mutex_lock(&adc->lock);
/* Mux in this channel */
val = ch->hwchan->amux_channel << ADC_AMUX_SEL_SHIFT;
val |= ch->hwchan->pre_scale_mux << ADC_AMUX_PREMUX_SHIFT;
ret = regmap_write(adc->map, ADC_ARB_USRP_AMUX_CNTRL, val);
if (ret)
goto unlock;
/* Set up ratiometric scale value, mask off all bits except these */
rsvmask = (ADC_ARB_USRP_RSV_RST | ADC_ARB_USRP_RSV_DTEST0 |
ADC_ARB_USRP_RSV_DTEST1 | ADC_ARB_USRP_RSV_OP);
if (adc->variant->broken_ratiometric && !force_ratiometric) {
/*
* Apparently the PM8058 has some kind of bug which is
* reflected in the vendor tree drivers/misc/pmix8058-xoadc.c
* which just hardcodes the RSV selector to SEL1 (0x20) for
* most cases and SEL0 (0x10) for the MUXOFF channel only.
* If we force ratiometric (currently only done when attempting
* to do ratiometric calibration) this doesn't seem to work
* very well and I suspect ratiometric conversion is simply
* broken or not supported on the PM8058.
*
* Maybe IO_SEL2 doesn't exist on PM8058 and bits 4 & 5 select
* the mode alone.
*
* Some PM8058 register documentation would be nice to get
* this right.
*/
if (ch->hwchan->amux_channel == PM8XXX_CHANNEL_MUXOFF)
rsvval = ADC_ARB_USRP_RSV_IP_SEL0;
else
rsvval = ADC_ARB_USRP_RSV_IP_SEL1;
} else {
if (rsv == 0xff)
rsvval = (ch->amux_ip_rsv << ADC_RSV_IP_SEL_SHIFT) |
ADC_ARB_USRP_RSV_TRM;
else
rsvval = (rsv << ADC_RSV_IP_SEL_SHIFT) |
ADC_ARB_USRP_RSV_TRM;
}
ret = regmap_update_bits(adc->map,
ADC_ARB_USRP_RSV,
~rsvmask,
rsvval);
if (ret)
goto unlock;
ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM,
ADC_ARB_USRP_ANA_PARAM_DIS);
if (ret)
goto unlock;
/* Decimation factor */
ret = regmap_write(adc->map, ADC_ARB_USRP_DIG_PARAM,
ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 |
ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 |
ch->decimation << ADC_DIG_PARAM_DEC_SHIFT);
if (ret)
goto unlock;
ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM,
ADC_ARB_USRP_ANA_PARAM_EN);
if (ret)
goto unlock;
/* Enable the arbiter, the Qualcomm code does it twice like this */
ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
ADC_ARB_USRP_CNTRL_EN_ARB);
if (ret)
goto unlock;
ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
ADC_ARB_USRP_CNTRL_EN_ARB);
if (ret)
goto unlock;
/* Fire a request! */
reinit_completion(&adc->complete);
ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
ADC_ARB_USRP_CNTRL_EN_ARB |
ADC_ARB_USRP_CNTRL_REQ);
if (ret)
goto unlock;
/* Next the interrupt occurs */
//.........这里部分代码省略.........
/**
* This function is used to calculate the divisors of psr, pm, fp and it is
* supposed to be called in set_dai_sysclk() and set_bclk().
*
* @ratio: desired overall ratio for the paticipating dividers
* @usefp: for HCK setting, there is no need to set fp divider
* @fp: bypass other dividers by setting fp directly if fp != 0
* @tx: current setting is for playback or capture
*/
static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
bool usefp, u32 fp)
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
maxfp = usefp ? 16 : 1;
if (usefp && fp)
goto out_fp;
if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
2 * 8 * 256 * maxfp);
return -EINVAL;
} else if (ratio % 2) {
dev_err(dai->dev, "the raio must be even if using upper divider\n");
return -EINVAL;
}
ratio /= 2;
psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
/* Set the max fluctuation -- 0.1% of the max devisor */
savesub = (psr ? 1 : 8) * 256 * maxfp / 1000;
/* Find the best value for PM */
for (i = 1; i <= 256; i++) {
for (j = 1; j <= maxfp; j++) {
/* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
prod = (psr ? 1 : 8) * i * j;
if (prod == ratio)
sub = 0;
else if (prod / ratio == 1)
sub = prod - ratio;
else if (ratio / prod == 1)
sub = ratio - prod;
else
continue;
/* Calculate the fraction */
sub = sub * 1000 / ratio;
if (sub < savesub) {
savesub = sub;
pm = i;
fp = j;
}
/* We are lucky */
if (savesub == 0)
goto out;
}
}
if (pm == 999) {
dev_err(dai->dev, "failed to calculate proper divisors\n");
return -EINVAL;
}
out:
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
psr | ESAI_xCCR_xPM(pm));
out_fp:
/* Bypass fp if not being required */
if (maxfp <= 1)
return 0;
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
return 0;
}
static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
{
int ret = 0;
unsigned int reg_val;
struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
imxpriv->gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
if (IS_ERR(imxpriv->gpr)) {
dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
return PTR_ERR(imxpriv->gpr);
}
ret = clk_prepare_enable(imxpriv->sata_ref_clk);
if (ret < 0) {
dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret);
return ret;
}
/*
* set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write
* is 0x07fffffd, and the other one write for setting
* the mpll_clk_en.
*/
regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
| IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK
| IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK
| IMX6Q_GPR13_SATA_SPD_MODE_MASK
| IMX6Q_GPR13_SATA_MPLL_SS_EN
| IMX6Q_GPR13_SATA_TX_ATTEN_MASK
| IMX6Q_GPR13_SATA_TX_BOOST_MASK
| IMX6Q_GPR13_SATA_TX_LVL_MASK
| IMX6Q_GPR13_SATA_TX_EDGE_RATE
, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB
| IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M
| IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F
| IMX6Q_GPR13_SATA_SPD_MODE_3P0G
| IMX6Q_GPR13_SATA_MPLL_SS_EN
| IMX6Q_GPR13_SATA_TX_ATTEN_9_16
| IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB
| IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
usleep_range(100, 200);
/*
* Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
* and IP vendor specific register HOST_TIMER1MS.
* Configure CAP_SSS (support stagered spin up).
* Implement the port0.
* Get the ahb clock rate, and configure the TIMER1MS register.
*/
reg_val = readl(mmio + HOST_CAP);
if (!(reg_val & HOST_CAP_SSS)) {
reg_val |= HOST_CAP_SSS;
writel(reg_val, mmio + HOST_CAP);
}
reg_val = readl(mmio + HOST_PORTS_IMPL);
if (!(reg_val & 0x1)) {
reg_val |= 0x1;
writel(reg_val, mmio + HOST_PORTS_IMPL);
}
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
writel(reg_val, mmio + HOST_TIMER1MS);
return 0;
}
开发者ID:03199618,项目名称:linux,代码行数:69,代码来源:ahci_imx.c
示例17: fsl_esai_set_dai_sysclk
/**
* This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
*
* @Parameters:
* clk_id: The clock source of HCKT/HCKR
* (Input from outside; output from inside, FSYS or EXTAL)
* freq: The required clock rate of HCKT/HCKR
* dir: The clock direction of HCKT/HCKR
*
* Note: If the direction is input, we do not care about clk_id.
*/
static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
struct clk *clksrc = esai_priv->extalclk;
bool tx = clk_id <= ESAI_HCKT_EXTAL;
bool in = dir == SND_SOC_CLOCK_IN;
u32 ret, ratio, ecr = 0;
unsigned long clk_rate;
/* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
esai_priv->sck_div[tx] = true;
/* Set the direction of HCKT/HCKR pins */
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
if (in)
goto out;
switch (clk_id) {
case ESAI_HCKT_FSYS:
case ESAI_HCKR_FSYS:
clksrc = esai_priv->fsysclk;
break;
case ESAI_HCKT_EXTAL:
ecr |= ESAI_ECR_ETI;
case ESAI_HCKR_EXTAL:
ecr |= ESAI_ECR_ERI;
break;
default:
return -EINVAL;
}
if (IS_ERR(clksrc)) {
dev_err(dai->dev, "no assigned %s clock\n",
clk_id % 2 ? "extal" : "fsys");
return PTR_ERR(clksrc);
}
clk_rate = clk_get_rate(clksrc);
ratio = clk_rate / freq;
if (ratio * freq > clk_rate)
ret = ratio * freq - clk_rate;
else if (ratio * freq < clk_rate)
ret = clk_rate - ratio * freq;
else
ret = 0;
/* Block if clock source can not be divided into the required rate */
if (ret != 0 && clk_rate / ret < 1000) {
dev_err(dai->dev, "failed to derive required HCK%c rate\n",
tx ? 'T' : 'R');
return -EINVAL;
}
/* Only EXTAL source can be output directly without using PSR and PM */
if (ratio == 1 && clksrc == esai_priv->extalclk) {
/* Bypass all the dividers if not being needed */
ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
goto out;
} else if (ratio < 2) {
/* The ratio should be no less than 2 if using other sources */
dev_err(dai->dev, "failed to derive required HCK%c rate\n",
tx ? 'T' : 'R');
return -EINVAL;
}
ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
if (ret)
return ret;
esai_priv->sck_div[tx] = false;
out:
esai_priv->hck_rate[tx] = freq;
regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :
ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
return 0;
}
请发表评论