summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/regmap/regmap.c9
-rw-r--r--drivers/input/misc/twl6040-vibra.c2
-rw-r--r--drivers/mfd/twl6040-core.c38
-rw-r--r--drivers/regulator/core.c59
4 files changed, 86 insertions, 22 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index cf3565cae93..2fa55c56897 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -37,6 +37,11 @@ struct regmap {
void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
+
+ unsigned int max_register;
+ bool (*writeable_reg)(struct device *dev, unsigned int reg);
+ bool (*readable_reg)(struct device *dev, unsigned int reg);
+ bool (*volatile_reg)(struct device *dev, unsigned int reg);
};
static void regmap_format_4_12_write(struct regmap *map,
@@ -116,6 +121,10 @@ struct regmap *regmap_init(struct device *dev,
map->format.val_bytes = config->val_bits / 8;
map->dev = dev;
map->bus = bus;
+ map->max_register = config->max_register;
+ map->writeable_reg = config->writeable_reg;
+ map->readable_reg = config->readable_reg;
+ map->volatile_reg = config->volatile_reg;
switch (config->reg_bits) {
case 4:
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index c43002e7ec7..154b7a324d6 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -97,7 +97,7 @@ static void twl6040_vibra_enable(struct vibra_info *info)
}
twl6040_power(info->twl6040, 1);
- if (twl6040->rev <= TWL6040_REV_ES1_1) {
+ if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) {
/*
* ERRATA: Disable overcurrent protection for at least
* 3ms when enabling vibrator drivers to avoid false
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index 24d436c2fe4..7dc8c471500 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -34,8 +34,6 @@
#include <linux/mfd/core.h>
#include <linux/mfd/twl6040.h>
-static struct platform_device *twl6040_dev;
-
int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
{
int ret;
@@ -203,11 +201,11 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data)
if (intid & TWL6040_THINT) {
status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
if (status & TWL6040_TSHUTDET) {
- dev_warn(&twl6040_dev->dev,
+ dev_warn(twl6040->dev,
"Thermal shutdown, powering-off");
twl6040_power(twl6040, 0);
} else {
- dev_warn(&twl6040_dev->dev,
+ dev_warn(twl6040->dev,
"Leaving thermal shutdown, powering-on");
twl6040_power(twl6040, 1);
}
@@ -227,7 +225,7 @@ static int twl6040_power_up_completion(struct twl6040 *twl6040,
if (!time_left) {
intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
if (!(intid & TWL6040_READYINT)) {
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"timeout waiting for READYINT\n");
return -ETIMEDOUT;
}
@@ -255,7 +253,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* wait for power-up completion */
ret = twl6040_power_up_completion(twl6040, naudint);
if (ret) {
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"automatic power-down failed\n");
twl6040->power_count = 0;
goto out;
@@ -264,7 +262,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* use manual power-up sequence */
ret = twl6040_power_up(twl6040);
if (ret) {
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"manual power-up failed\n");
twl6040->power_count = 0;
goto out;
@@ -276,7 +274,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
} else {
/* already powered-down */
if (!twl6040->power_count) {
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"device is already powered-off\n");
ret = -EPERM;
goto out;
@@ -326,7 +324,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
lppllctl &= ~TWL6040_LPLLFIN;
break;
default:
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"freq_out %d not supported\n", freq_out);
ret = -EINVAL;
goto pll_out;
@@ -347,7 +345,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
hppllctl);
break;
default:
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"freq_in %d not supported\n", freq_in);
ret = -EINVAL;
goto pll_out;
@@ -356,7 +354,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
case TWL6040_SYSCLK_SEL_HPPLL:
/* high-performance PLL can provide only 19.2 MHz */
if (freq_out != 19200000) {
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"freq_out %d not supported\n", freq_out);
ret = -EINVAL;
goto pll_out;
@@ -389,7 +387,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
TWL6040_HPLLENA;
break;
default:
- dev_err(&twl6040_dev->dev,
+ dev_err(twl6040->dev,
"freq_in %d not supported\n", freq_in);
ret = -EINVAL;
goto pll_out;
@@ -406,7 +404,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
break;
default:
- dev_err(&twl6040_dev->dev, "unknown pll id %d\n", pll_id);
+ dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
ret = -EINVAL;
goto pll_out;
}
@@ -471,9 +469,7 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, twl6040);
- twl6040_dev = pdev;
twl6040->dev = &pdev->dev;
- twl6040->audpwron = pdata->audpwron_gpio;
twl6040->irq = pdata->naudint_irq;
twl6040->irq_base = pdata->irq_base;
@@ -483,6 +479,12 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
+ /* ERRATA: Automatic power-up is not possible in ES1.0 */
+ if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
+ twl6040->audpwron = pdata->audpwron_gpio;
+ else
+ twl6040->audpwron = -EINVAL;
+
if (gpio_is_valid(twl6040->audpwron)) {
ret = gpio_request(twl6040->audpwron, "audpwron");
if (ret)
@@ -493,10 +495,6 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
goto gpio2_err;
}
- /* ERRATA: Automatic power-up is not possible in ES1.0 */
- if (twl6040->rev == TWL6040_REV_ES1_0)
- twl6040->audpwron = -EINVAL;
-
/* codec interrupt */
ret = twl6040_irq_init(twl6040);
if (ret)
@@ -566,7 +564,6 @@ gpio2_err:
gpio1_err:
platform_set_drvdata(pdev, NULL);
kfree(twl6040);
- twl6040_dev = NULL;
return ret;
}
@@ -586,7 +583,6 @@ static int __devexit twl6040_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(twl6040);
- twl6040_dev = NULL;
return 0;
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d8e6a429e8b..d0bde70f346 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1552,6 +1552,63 @@ int regulator_force_disable(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_force_disable);
+static void regulator_disable_work(struct work_struct *work)
+{
+ struct regulator_dev *rdev = container_of(work, struct regulator_dev,
+ disable_work.work);
+ int count, i, ret;
+
+ mutex_lock(&rdev->mutex);
+
+ BUG_ON(!rdev->deferred_disables);
+
+ count = rdev->deferred_disables;
+ rdev->deferred_disables = 0;
+
+ for (i = 0; i < count; i++) {
+ ret = _regulator_disable(rdev);
+ if (ret != 0)
+ rdev_err(rdev, "Deferred disable failed: %d\n", ret);
+ }
+
+ mutex_unlock(&rdev->mutex);
+
+ if (rdev->supply) {
+ for (i = 0; i < count; i++) {
+ ret = regulator_disable(rdev->supply);
+ if (ret != 0) {
+ rdev_err(rdev,
+ "Supply disable failed: %d\n", ret);
+ }
+ }
+ }
+}
+
+/**
+ * regulator_disable_deferred - disable regulator output with delay
+ * @regulator: regulator source
+ * @ms: miliseconds until the regulator is disabled
+ *
+ * Execute regulator_disable() on the regulator after a delay. This
+ * is intended for use with devices that require some time to quiesce.
+ *
+ * NOTE: this will only disable the regulator output if no other consumer
+ * devices have it enabled, the regulator device supports disabling and
+ * machine constraints permit this operation.
+ */
+int regulator_disable_deferred(struct regulator *regulator, int ms)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+
+ mutex_lock(&rdev->mutex);
+ rdev->deferred_disables++;
+ mutex_unlock(&rdev->mutex);
+
+ return schedule_delayed_work(&rdev->disable_work,
+ msecs_to_jiffies(ms));
+}
+EXPORT_SYMBOL_GPL(regulator_disable_deferred);
+
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
/* If we don't know then assume that the regulator is always on */
@@ -2622,6 +2679,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
INIT_LIST_HEAD(&rdev->consumer_list);
INIT_LIST_HEAD(&rdev->list);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+ INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
/* preform any regulator specific init */
if (init_data->regulator_init) {
@@ -2729,6 +2787,7 @@ void regulator_unregister(struct regulator_dev *rdev)
#ifdef CONFIG_DEBUG_FS
debugfs_remove_recursive(rdev->debugfs);
#endif
+ flush_work_sync(&rdev->disable_work.work);
WARN_ON(rdev->open_count);
unset_regulator_supplies(rdev);
list_del(&rdev->list);