/** * wm8350_hp_jack_detect - Enable headphone jack detection. * * @codec: WM8350 codec * @which: left or right jack detect signal * @jack: jack to report detection events on * @report: value to report * * Enables the headphone jack detection of the WM8350. */ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, struct snd_soc_jack *jack, int report) { struct wm8350_data *priv = codec->private_data; struct wm8350 *wm8350 = codec->control_data; int irq; int ena; switch (which) { case WM8350_JDL: priv->hpl.jack = jack; priv->hpl.report = report; irq = WM8350_IRQ_CODEC_JCK_DET_L; ena = WM8350_JDL_ENA; break; case WM8350_JDR: priv->hpr.jack = jack; priv->hpr.report = report; irq = WM8350_IRQ_CODEC_JCK_DET_R; ena = WM8350_JDR_ENA; break; default: return -EINVAL; } wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); /* Sync status */ wm8350_hp_jack_handler(irq, priv); return 0; }
static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350* wm8350 = codec->control_data; u16 fll_4; switch(clk_id) { case WM8350_MCLK_SEL_MCLK: wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1, WM8350_MCLK_SEL); break; case WM8350_MCLK_SEL_PLL_MCLK: case WM8350_MCLK_SEL_PLL_DAC: case WM8350_MCLK_SEL_PLL_ADC: case WM8350_MCLK_SEL_PLL_32K: wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1, WM8350_MCLK_SEL); fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & ~WM8350_FLL_CLK_SRC_MASK; wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id); break; } /* MCLK direction */ if (dir == WM8350_MCLK_DIR_OUT) wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_MCLK_DIR); else wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_MCLK_DIR); return 0; }
static int wm8350_set_fll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350 *wm8350 = codec->control_data; struct wm8350_data *priv = codec->private_data; struct _fll_div fll_div; int ret = 0; u16 fll_1, fll_4; if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out) return 0; /* power down FLL - we need to do this for reconfiguration */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); if (freq_out == 0 || freq_in == 0) return ret; ret = fll_factors(&fll_div, freq_in, freq_out); if (ret < 0) return ret; dev_dbg(wm8350->dev, "FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d", freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div, fll_div.ratio); /* set up N.K & dividers */ fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) & ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000); wm8350_codec_write(codec, WM8350_FLL_CONTROL_1, fll_1 | (fll_div.div << 8) | 0x50); wm8350_codec_write(codec, WM8350_FLL_CONTROL_2, (fll_div.ratio << 11) | (fll_div. n & WM8350_FLL_N_MASK)); wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k); fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF); wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) | (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0)); /* power FLL on */ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); priv->fll_freq_out = freq_out; priv->fll_freq_in = freq_in; return 0; }
static int imx_3stack_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->card->codec; struct wm8350 *wm8350 = codec->control_data; struct imx_3stack_priv *priv = &machine_priv; /* In master mode the LR clock can come from either the DAC or ADC. * We use the LR clock from whatever stream is enabled first. */ if (!priv->lr_clk_active) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_LRC_ADC_SEL); else wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_LRC_ADC_SEL); } priv->lr_clk_active++; if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) priv->capture_active = 1; else priv->playback_active = 1; return 0; }
static void imx_3stack_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->card->codec; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct imx_3stack_priv *priv = &machine_priv; struct wm8350 *wm8350 = codec->control_data; /* disable the PLL if there are no active Tx or Rx channels */ if (!codec_dai->active) snd_soc_dai_set_pll(codec_dai, 0, 0, 0); priv->lr_clk_active--; /* * We need to keep track of active streams in master mode and * switch LRC source if necessary. */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) priv->capture_active = 0; else priv->playback_active = 0; if (priv->capture_active) wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_LRC_ADC_SEL); else if (priv->playback_active) wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_LRC_ADC_SEL); }
static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable) { int reg = 0, ret; switch (dcdc) { case WM8350_DCDC_1: reg = WM8350_DCDC1_FORCE_PWM; break; case WM8350_DCDC_3: reg = WM8350_DCDC3_FORCE_PWM; break; case WM8350_DCDC_4: reg = WM8350_DCDC4_FORCE_PWM; break; case WM8350_DCDC_6: reg = WM8350_DCDC6_FORCE_PWM; break; default: return -EINVAL; } if (enable) ret = wm8350_set_bits(wm8350, reg, WM8350_DCDC1_FORCE_PWM_ENA); else ret = wm8350_clear_bits(wm8350, reg, WM8350_DCDC1_FORCE_PWM_ENA); return ret; }
static int config_hibernate(struct wm8350 *wm8350) { struct wm8350_pmic *pmic = &wm8350->pmic; /* dont assert RTS when hibernating */ wm8350_set_bits(wm8350, WM8350_SYSTEM_HIBERNATE, WM8350_RST_HIB_MODE); /* set up hibernate voltages -- needs refining */ wm8350_dcdc_set_image_voltage(pmic, WM8350_DCDC_1, 1400, /*1200, *//* 1.0v for mx32 */ WM8350_DCDC_HIB_MODE_IMAGE, WM8350_DCDC_HIB_SIG_REG); wm8350_dcdc_set_image_voltage(pmic, WM8350_DCDC_3, 2800, WM8350_DCDC_HIB_MODE_IMAGE, WM8350_DCDC_HIB_SIG_REG); wm8350_dcdc_set_image_voltage(pmic, WM8350_DCDC_4, 1800, WM8350_DCDC_HIB_MODE_IMAGE, WM8350_DCDC_HIB_SIG_REG); wm8350_dcdc_set_image_voltage(pmic, WM8350_DCDC_6, 1800, WM8350_DCDC_HIB_MODE_IMAGE, WM8350_DCDC_HIB_SIG_REG); wm8350_ldo_set_image_voltage(pmic, WM8350_LDO_1, 2800, WM8350_LDO_HIB_MODE_IMAGE, WM8350_LDO_HIB_SIG_REG); wm8350_ldo_set_image_voltage(pmic, WM8350_LDO_2, 3300, WM8350_LDO_HIB_MODE_IMAGE, WM8350_LDO_HIB_SIG_REG); wm8350_ldo_set_image_voltage(pmic, WM8350_LDO_3, 1500, WM8350_LDO_HIB_MODE_IMAGE, WM8350_LDO_HIB_SIG_REG); wm8350_ldo_set_image_voltage(pmic, WM8350_LDO_4, 2500, WM8350_LDO_HIB_MODE_IMAGE, WM8350_LDO_HIB_MODE_DIS); return 0; }
static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert) { if (invert == WM8350_GPIO_INVERT_ON) return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio); else return wm8350_clear_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio); }
static irqreturn_t wm8350_charger_handler(int irq, void *data) { struct wm8350 *wm8350 = data; struct wm8350_power *power = &wm8350->power; struct wm8350_charger_policy *policy = power->policy; switch (irq - wm8350->irq_base) { case WM8350_IRQ_CHG_BAT_FAIL: dev_err(wm8350->dev, "battery failed\n"); break; case WM8350_IRQ_CHG_TO: dev_err(wm8350->dev, "charger timeout\n"); power_supply_changed(&power->battery); break; case WM8350_IRQ_CHG_BAT_HOT: case WM8350_IRQ_CHG_BAT_COLD: case WM8350_IRQ_CHG_START: case WM8350_IRQ_CHG_END: power_supply_changed(&power->battery); break; case WM8350_IRQ_CHG_FAST_RDY: dev_dbg(wm8350->dev, "fast charger ready\n"); wm8350_charger_config(wm8350, policy); wm8350_reg_unlock(wm8350); wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, WM8350_CHG_FAST); wm8350_reg_lock(wm8350); break; case WM8350_IRQ_CHG_VBATT_LT_3P9: dev_warn(wm8350->dev, "battery < 3.9V\n"); break; case WM8350_IRQ_CHG_VBATT_LT_3P1: dev_warn(wm8350->dev, "battery < 3.1V\n"); break; case WM8350_IRQ_CHG_VBATT_LT_2P85: dev_warn(wm8350->dev, "battery < 2.85V\n"); break; /* Supply change. We will overnotify but it should do * no harm. */ case WM8350_IRQ_EXT_USB_FB: case WM8350_IRQ_EXT_WALL_FB: wm8350_charger_config(wm8350, policy); case WM8350_IRQ_EXT_BAT_FB: /* Fall through */ power_supply_changed(&power->battery); power_supply_changed(&power->usb); power_supply_changed(&power->ac); break; default: dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); } return IRQ_HANDLED; }
static __devinit int wm8350_power_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_power *power = &wm8350->power; struct wm8350_charger_policy *policy = power->policy; struct power_supply *usb = &power->usb; struct power_supply *battery = &power->battery; struct power_supply *ac = &power->ac; int ret; ac->name = "wm8350-ac"; ac->type = POWER_SUPPLY_TYPE_MAINS; ac->properties = wm8350_ac_props; ac->num_properties = ARRAY_SIZE(wm8350_ac_props); ac->get_property = wm8350_ac_get_prop; ret = power_supply_register(&pdev->dev, ac); if (ret) return ret; battery->name = "wm8350-battery"; battery->properties = wm8350_bat_props; battery->num_properties = ARRAY_SIZE(wm8350_bat_props); battery->get_property = wm8350_bat_get_property; battery->use_for_apm = 1; ret = power_supply_register(&pdev->dev, battery); if (ret) goto battery_failed; usb->name = "wm8350-usb", usb->type = POWER_SUPPLY_TYPE_USB; usb->properties = wm8350_usb_props; usb->num_properties = ARRAY_SIZE(wm8350_usb_props); usb->get_property = wm8350_usb_get_prop; ret = power_supply_register(&pdev->dev, usb); if (ret) goto usb_failed; ret = device_create_file(&pdev->dev, &dev_attr_charger_state); if (ret < 0) dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret); ret = 0; wm8350_init_charger(wm8350); if (wm8350_charger_config(wm8350, policy) == 0) { wm8350_reg_unlock(wm8350); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA); wm8350_reg_lock(wm8350); } return ret; usb_failed: power_supply_unregister(battery); battery_failed: power_supply_unregister(ac); return ret; }
static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db) { if (db == WM8350_GPIO_DEBOUNCE_ON) return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE, 1 << gpio); else return wm8350_clear_bits(wm8350, WM8350_GPIO_DEBOUNCE, 1 << gpio); }
static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int dcdc = rdev_get_id(rdev); u16 val; if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6) return -EINVAL; if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5) return -EINVAL; val = 1 << (dcdc - WM8350_DCDC_1); switch (mode) { case REGULATOR_MODE_FAST: /* force continuous mode */ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val); wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val); force_continuous_enable(wm8350, dcdc, 1); break; case REGULATOR_MODE_NORMAL: /* active / pulse skipping */ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val); wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val); force_continuous_enable(wm8350, dcdc, 0); break; case REGULATOR_MODE_IDLE: /* standby mode */ force_continuous_enable(wm8350, dcdc, 0); wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val); wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val); break; case REGULATOR_MODE_STANDBY: /* LDO mode */ force_continuous_enable(wm8350, dcdc, 0); wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val); break; } return 0; }
static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol) { if (pol == WM8350_GPIO_ACTIVE_HIGH) return wm8350_set_bits(wm8350, WM8350_GPIO_PIN_POLARITY_TYPE, 1 << gpio); else return wm8350_clear_bits(wm8350, WM8350_GPIO_PIN_POLARITY_TYPE, 1 << gpio); }
static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down) { if (down) return wm8350_set_bits(wm8350, WM8350_GPIO_PULL_DOWN_CONTROL, 1 << gpio); else return wm8350_clear_bits(wm8350, WM8350_GPIO_PULL_DOWN_CONTROL, 1 << gpio); }
static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up) { if (up) return wm8350_set_bits(wm8350, WM8350_GPIO_PIN_PULL_UP_CONTROL, 1 << gpio); else return wm8350_clear_bits(wm8350, WM8350_GPIO_PIN_PULL_UP_CONTROL, 1 << gpio); }
static int wm8350_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; struct wm8350* wm8350 = codec->control_data; if (mute) wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); else wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); return 0; }
static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data) { struct wm8350_power *power = &wm8350->power; struct wm8350_charger_policy *policy = power->policy; switch (irq) { case WM8350_IRQ_CHG_BAT_FAIL: dev_err(wm8350->dev, "battery failed\n"); break; case WM8350_IRQ_CHG_TO: dev_err(wm8350->dev, "charger timeout\n"); power_supply_changed(&power->battery); break; case WM8350_IRQ_CHG_BAT_HOT: case WM8350_IRQ_CHG_BAT_COLD: case WM8350_IRQ_CHG_START: case WM8350_IRQ_CHG_END: power_supply_changed(&power->battery); break; case WM8350_IRQ_CHG_FAST_RDY: dev_dbg(wm8350->dev, "fast charger ready\n"); wm8350_charger_config(wm8350, policy); wm8350_reg_unlock(wm8350); wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, WM8350_CHG_FAST); wm8350_reg_lock(wm8350); break; case WM8350_IRQ_CHG_VBATT_LT_3P9: dev_warn(wm8350->dev, "battery < 3.9V\n"); break; case WM8350_IRQ_CHG_VBATT_LT_3P1: dev_warn(wm8350->dev, "battery < 3.1V\n"); break; case WM8350_IRQ_CHG_VBATT_LT_2P85: dev_warn(wm8350->dev, "battery < 2.85V\n"); break; case WM8350_IRQ_EXT_USB_FB: case WM8350_IRQ_EXT_WALL_FB: wm8350_charger_config(wm8350, policy); case WM8350_IRQ_EXT_BAT_FB: power_supply_changed(&power->battery); power_supply_changed(&power->usb); power_supply_changed(&power->ac); break; default: dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); } }
static int wm8350_codec_io_probe(struct snd_soc_codec *codec, struct snd_soc_machine *machine) { struct wm8350* wm8350 = codec->control_data; struct wm8350_out_ramp *or = codec->private_data; struct wm8350_output *out1 = &or->out1, *out2 = &or->out2; snd_assert(wm8350 != NULL, return -EINVAL); /* reset codec */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); /* enable clock gen - lg need to move in new silicon */ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_SYSCLK_ENA); /* charge output caps */ codec->dapm_state = SNDRV_CTL_POWER_D3cold; wm8350_dapm_event(codec, SNDRV_CTL_POWER_D3hot); wm8350_add_controls(codec, machine->card); wm8350_add_widgets(codec, machine); /* read OUT1 & OUT2 volumes */ out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0); wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0); wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU); wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0); wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0); wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU); return 0; }
static int wm8350_set_fll(struct snd_soc_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350* wm8350 = codec->control_data; struct _fll_div fll_div; int ret = 0; u16 fll_1, fll_4; if (freq_out == 0 || freq_in == 0) { /* power down FLL */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); return ret; } ret = fll_factors(&fll_div, freq_in, freq_out); if (ret < 0) return ret; /* set up N.K & dividers */ fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) & ~(WM8350_FLL_OUTDIV_MASK | 0xc000); wm8350_codec_write(codec, WM8350_FLL_CONTROL_1, fll_1 | (fll_div.div << 8)); wm8350_codec_write(codec, WM8350_FLL_CONTROL_2, (fll_div.ratio << 11) | (fll_div.n & WM8350_FLL_N_MASK)); wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k); fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF); wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) | (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0)); /* power FLL on */ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); /* do we need to wait here ? */ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); return 0; }
/** * wm8350_mic_jack_detect - Enable microphone jack detection. * * @codec: WM8350 codec * @jack: jack to report detection events on * @detect_report: value to report when presence detected * @short_report: value to report when microphone short detected * * Enables the microphone jack detection of the WM8350. If both reports * are specified as zero then detection is disabled. */ int wm8350_mic_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int detect_report, int short_report) { struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); struct wm8350 *wm8350 = codec->control_data; priv->mic.jack = jack; priv->mic.report = detect_report; priv->mic.short_report = short_report; if (detect_report || short_report) { wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1, WM8350_MIC_DET_ENA); } else { wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1, WM8350_MIC_DET_ENA); } return 0; }
static int wm8350_ldo_enable(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int ldo = rdev_get_id(rdev); u16 shift; if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4) return -EINVAL; shift = (ldo - WM8350_LDO_1) + 8; wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); return 0; }
static int wm8350_dcdc_enable(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int dcdc = rdev_get_id(rdev); u16 shift; if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6) return -EINVAL; shift = dcdc - WM8350_DCDC_1; wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift); return 0; }
static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq, void *data) { struct rtc_device *rtc = wm8350->rtc.rtc; int ret; rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); /* Make it one shot */ ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_ALMSET); if (ret != 0) { dev_err(&(wm8350->rtc.pdev->dev), "Failed to disable alarm: %d\n", ret); } }
static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir) { int ret; wm8350_reg_unlock(wm8350); if (dir == WM8350_GPIO_DIR_OUT) ret = wm8350_clear_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, 1 << gpio); else ret = wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, 1 << gpio); wm8350_reg_lock(wm8350); return ret; }
/* * Set current time and date in RTC */ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm) { struct wm8350_rtc *wm_rtc = to_wm8350_rtc_device(dev); struct wm8350 *wm8350 = to_wm8350_from_rtc(wm_rtc); u16 time[4]; u16 rtc_ctrl; int ret, retries = WM8350_SET_TIME_RETRIES; dbg("%s tm->tm_wday %d, tm->tm_mon %d", __FUNCTION__, tm->tm_wday, tm->tm_mon); time[0] = tm->tm_sec; time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT; time[1] = tm->tm_hour; time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT; time[2] = tm->tm_mday; time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT; time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT; time[3] |= (tm->tm_year + 1900) % 100; /* Set RTC_SET to stop the clock */ ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET); if (ret < 0) return ret; /* Wait until confirmation of stopping */ do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_interruptible(msecs_to_jiffies(1)); } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS)); if (!retries) { printk(KERN_ERR "wm8350-rtc time out on set confirmation\n"); return -EIO; } /* Write time to RTC */ ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time); if (ret < 0) return ret; /* Clear RTC_SET to start the clock */ ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET); return ret; }
/* * Set current time and date in RTC */ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm) { struct wm8350 *wm8350 = dev_get_drvdata(dev); u16 time[4]; u16 rtc_ctrl; int ret, retries = WM8350_SET_TIME_RETRIES; time[0] = tm->tm_sec; time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT; time[1] = tm->tm_hour; time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT; time[2] = tm->tm_mday; time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT; time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT; time[3] |= (tm->tm_year + 1900) % 100; dev_dbg(dev, "Setting: %04x %04x %04x %04x\n", time[0], time[1], time[2], time[3]); /* Set RTC_SET to stop the clock */ ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET); if (ret < 0) return ret; /* Wait until confirmation of stopping */ do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_uninterruptible(msecs_to_jiffies(1)); } while (--retries && !(rtc_ctrl & WM8350_RTC_STS)); if (!retries) { dev_err(dev, "timed out on set confirmation\n"); return -EIO; } /* Write time to RTC */ ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time); if (ret < 0) return ret; /* Clear RTC_SET to start the clock */ ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET); return ret; }
static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350 *wm8350 = codec->control_data; u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & ~WM8350_AIF_WL_MASK; /* bit size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: iface |= 0x1 << 10; break; case SNDRV_PCM_FORMAT_S24_LE: iface |= 0x2 << 10; break; case SNDRV_PCM_FORMAT_S32_LE: iface |= 0x3 << 10; break; } wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); /* The sloping stopband filter is recommended for use with * lower sample rates to improve performance. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (params_rate(params) < 24000) wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME, WM8350_DAC_SB_FILT); else wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME, WM8350_DAC_SB_FILT); } return 0; }
/* * Set alarm time and date in RTC */ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct wm8350_rtc *wm_rtc = to_wm8350_rtc_device(dev); struct wm8350 *wm8350 = to_wm8350_from_rtc(wm_rtc); struct rtc_time *tm = &alrm->time; u16 rtc_ctrl; u16 time[3]; int ret, retries = WM8350_SET_ALM_RETRIES; time[0] = tm->tm_sec; time[0] |= tm->tm_min << WM8350_RTC_ALMMINS_SHIFT; time[1] = tm->tm_hour; time[1] |= WM8350_RTC_ALMDAY_MASK; time[2] = WM8350_RTC_ALMDATE_MASK; time[2] |= WM8350_RTC_ALMMTH_MASK; /* Set RTC_SET to stop the clock */ ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_ALMSET); if (ret < 0) return ret; /* Wait until confirmation of stopping */ do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_interruptible(msecs_to_jiffies(1)); } while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS)); /* Write time to RTC */ ret = wm8350_block_write(wm8350, WM8350_ALARM_SECONDS_MINUTES, 3, time); if (ret < 0) return ret; /* Clear RTC_ALMSET to enable the alarm */ ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_ALMSET); return ret; }
static int wm8350_rtc_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_rtc *wm_rtc = &wm8350->rtc; int ret = 0; /* enable the RTC */ ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_RTC_TICK_ENA); if (ret < 0) { printk(KERN_ERR "wm8350-rtc: failed to enable RTC\n"); return ret; } wm_rtc->rtc = rtc_device_register("wm8350-rtc", &pdev->dev, &wm8350_rtc_ops, THIS_MODULE); if (IS_ERR(wm_rtc->rtc)) { printk(KERN_ERR "wm8350-rtc: failed to register RTC/n"); return PTR_ERR(wm_rtc->rtc); } printk("wm8350: RTC version %s\n", WM8350_RTC_VERSION); wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350_rtc_update_handler, NULL); wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350_rtc_alarm_handler, NULL); if (wm_rtc->per_irq) { ret = request_irq(wm_rtc->per_irq, wm8350_rtc_periodic_irq, IRQF_DISABLED, "wm8350-rtc timer", &pdev->dev); if (ret < 0) { printk(KERN_ERR "wm8350-rtc: failed to get timer irq %d\n", wm_rtc->per_irq); wm_rtc->per_irq = 0; } } return 0; }
static int wm8350_rtc_stop_alarm(struct wm8350 *wm8350) { int retries = WM8350_SET_ALM_RETRIES; u16 rtc_ctrl; int ret; /* Set RTC_SET to stop the clock */ ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_ALMSET); if (ret < 0) return ret; /* Wait until confirmation of stopping */ do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_uninterruptible(msecs_to_jiffies(1)); } while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS)); if (!(rtc_ctrl & WM8350_RTC_ALMSTS)) return -ETIMEDOUT; return 0; }