|
@@ -21,6 +21,8 @@
|
|
|
#include <linux/regulator/machine.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/workqueue.h>
|
|
|
+#include <sound/soc.h>
|
|
|
|
|
|
#include <linux/mfd/arizona/core.h>
|
|
|
#include <linux/mfd/arizona/pdata.h>
|
|
@@ -34,6 +36,8 @@ struct arizona_micsupp {
|
|
|
|
|
|
struct regulator_consumer_supply supply;
|
|
|
struct regulator_init_data init_data;
|
|
|
+
|
|
|
+ struct work_struct check_cp_work;
|
|
|
};
|
|
|
|
|
|
static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
|
|
@@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
|
|
|
return selector;
|
|
|
}
|
|
|
|
|
|
+static void arizona_micsupp_check_cp(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct arizona_micsupp *micsupp =
|
|
|
+ container_of(work, struct arizona_micsupp, check_cp_work);
|
|
|
+ struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
|
|
|
+ struct arizona *arizona = micsupp->arizona;
|
|
|
+ struct regmap *regmap = arizona->regmap;
|
|
|
+ unsigned int reg;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, ®);
|
|
|
+ if (ret != 0) {
|
|
|
+ dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dapm) {
|
|
|
+ if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
|
|
|
+ ARIZONA_CPMIC_ENA)
|
|
|
+ snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
|
|
|
+ else
|
|
|
+ snd_soc_dapm_disable_pin(dapm, "MICSUPP");
|
|
|
+
|
|
|
+ snd_soc_dapm_sync(dapm);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int arizona_micsupp_enable(struct regulator_dev *rdev)
|
|
|
+{
|
|
|
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = regulator_enable_regmap(rdev);
|
|
|
+
|
|
|
+ if (ret == 0)
|
|
|
+ schedule_work(&micsupp->check_cp_work);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int arizona_micsupp_disable(struct regulator_dev *rdev)
|
|
|
+{
|
|
|
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = regulator_disable_regmap(rdev);
|
|
|
+ if (ret == 0)
|
|
|
+ schedule_work(&micsupp->check_cp_work);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
|
|
|
+{
|
|
|
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = regulator_set_bypass_regmap(rdev, ena);
|
|
|
+ if (ret == 0)
|
|
|
+ schedule_work(&micsupp->check_cp_work);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static struct regulator_ops arizona_micsupp_ops = {
|
|
|
- .enable = regulator_enable_regmap,
|
|
|
- .disable = regulator_disable_regmap,
|
|
|
+ .enable = arizona_micsupp_enable,
|
|
|
+ .disable = arizona_micsupp_disable,
|
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
|
|
|
|
.list_voltage = arizona_micsupp_list_voltage,
|
|
@@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = {
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
|
|
.get_bypass = regulator_get_bypass_regmap,
|
|
|
- .set_bypass = regulator_set_bypass_regmap,
|
|
|
+ .set_bypass = arizona_micsupp_set_bypass,
|
|
|
};
|
|
|
|
|
|
static const struct regulator_desc arizona_micsupp = {
|
|
@@ -109,7 +177,8 @@ static const struct regulator_desc arizona_micsupp = {
|
|
|
static const struct regulator_init_data arizona_micsupp_default = {
|
|
|
.constraints = {
|
|
|
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
|
|
|
- REGULATOR_CHANGE_VOLTAGE,
|
|
|
+ REGULATOR_CHANGE_VOLTAGE |
|
|
|
+ REGULATOR_CHANGE_BYPASS,
|
|
|
.min_uV = 1700000,
|
|
|
.max_uV = 3300000,
|
|
|
},
|
|
@@ -131,6 +200,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
micsupp->arizona = arizona;
|
|
|
+ INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
|
|
|
|
|
|
/*
|
|
|
* Since the chip usually supplies itself we provide some
|