#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/leds.h>
-#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/fixed.h>
struct modem_private_data {
struct regulator *regulator;
- struct {
- struct mutex lock;
- bool enabled;
- } consumer;
};
-static int regulator_toggle(struct modem_private_data *priv, bool enable)
-{
- int err = 0;
-
- mutex_lock(&priv->consumer.lock);
- if (IS_ERR(priv->regulator)) {
- err = PTR_ERR(priv->regulator);
- } else if (enable) {
- if (!priv->consumer.enabled) {
- err = regulator_enable(priv->regulator);
- priv->consumer.enabled = true;
- }
- } else {
- if (priv->consumer.enabled) {
- err = regulator_disable(priv->regulator);
- priv->consumer.enabled = false;
- }
- }
- mutex_unlock(&priv->consumer.lock);
-
- return err;
-}
-
static struct modem_private_data modem_priv;
void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value)
for (; bit < ngpio; bit++, bitpos = bitpos << 1) {
if (!(mask & bitpos))
continue;
- else if (base + bit == AMS_DELTA_GPIO_PIN_MODEM_NRESET)
- regulator_toggle(&modem_priv, (value & bitpos) != 0);
else
gpio_set_value(base + bit, (value & bitpos) != 0);
}
{
struct modem_private_data *priv = port->private_data;
+ if (IS_ERR(priv->regulator))
+ return;
+
if (state == old)
return;
- regulator_toggle(priv, state == 0);
+ if (state == 0)
+ regulator_enable(priv->regulator);
+ else if (old == 0)
+ regulator_disable(priv->regulator);
}
static struct plat_serial8250_port ams_delta_modem_ports[] = {
gpio_direction_input(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
/* Initialize the modem_nreset regulator consumer before use */
- mutex_init(&modem_priv.consumer.lock);
modem_priv.regulator = ERR_PTR(-ENODEV);
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC,
/*
* Once the modem device is registered, the modem_nreset
* regulator can be requested on behalf of that device.
- * In addition to the modem .pm callback, that regulator
- * is still used via the ams_delta_latch_write() wrapper
- * by the ASoC driver until updated.
*/
modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev,
"RESET#");
};
-/* Board specific codec bias level control */
-static int ams_delta_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level)
-{
- switch (level) {
- case SND_SOC_BIAS_ON:
- case SND_SOC_BIAS_PREPARE:
- case SND_SOC_BIAS_STANDBY:
- if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
- ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
- AMS_DELTA_LATCH2_MODEM_NRESET);
- break;
- case SND_SOC_BIAS_OFF:
- if (card->dapm.bias_level != SND_SOC_BIAS_OFF)
- ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
- 0);
- }
- card->dapm.bias_level = level;
-
- return 0;
-}
-
/* Digital mute implemented using modem/CPU multiplexer.
* Shares hardware with codec config pulse generation */
static bool ams_delta_muted = 1;
ams_delta_ops.shutdown = ams_delta_shutdown;
}
- /* Set codec bias level */
- ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
-
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
ret = snd_soc_jack_new(rtd->codec, "hook_switch",
.owner = THIS_MODULE,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
- .set_bias_level = ams_delta_set_bias_level,
};
/* Module init/exit */
ARRAY_SIZE(ams_delta_hook_switch_gpios),
ams_delta_hook_switch_gpios);
- /* Keep modem power on */
- ams_delta_set_bias_level(&ams_delta_audio_card,
- &ams_delta_audio_card.rtd[0].codec->dapm,
- SND_SOC_BIAS_STANDBY);
-
platform_device_unregister(cx20442_platform_device);
platform_device_unregister(ams_delta_audio_platform_device);
}