@@ -1,3 +1,3 @@
# Makefile for device boot constraints
-obj-y := core.o
+obj-y := core.o supply.o
@@ -105,6 +105,10 @@ static struct constraint *constraint_allocate(struct constraint_dev *cdev,
void (*remove)(struct constraint *constraint);
switch (type) {
+ case DEV_BOOT_CONSTRAINT_SUPPLY:
+ add = constraint_supply_add;
+ remove = constraint_supply_remove;
+ break;
default:
return ERR_PTR(-EINVAL);
}
@@ -30,4 +30,7 @@ struct constraint {
};
/* Forward declarations of constraint specific callbacks */
+int constraint_supply_add(struct constraint *constraint, void *data);
+void constraint_supply_remove(struct constraint *constraint);
+
#endif /* _CORE_H */
new file mode 100644
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#define pr_fmt(fmt) "Supply Boot Constraints: " fmt
+
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include "core.h"
+
+struct constraint_supply {
+ struct dev_boot_constraint_supply_info supply;
+ struct regulator *reg;
+};
+
+int constraint_supply_add(struct constraint *constraint, void *data)
+{
+ struct dev_boot_constraint_supply_info *supply = data;
+ struct constraint_supply *csupply;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ csupply = kzalloc(sizeof(*csupply), GFP_KERNEL);
+ if (!csupply)
+ return -ENOMEM;
+
+ csupply->reg = regulator_get(dev, supply->name);
+ if (IS_ERR(csupply->reg)) {
+ ret = PTR_ERR(csupply->reg);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(dev, "regulator_get() failed for %s (%d)\n",
+ supply->name, ret);
+ }
+ goto free;
+ }
+
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0) {
+ ret = regulator_set_voltage(csupply->reg, supply->u_volt_min,
+ supply->u_volt_max);
+ if (ret) {
+ dev_err(dev, "regulator_set_voltage %s failed (%d)\n",
+ supply->name, ret);
+ goto free_regulator;
+ }
+ }
+
+ ret = regulator_enable(csupply->reg);
+ if (ret) {
+ dev_err(dev, "regulator_enable %s failed (%d)\n",
+ supply->name, ret);
+ goto remove_voltage;
+ }
+
+ memcpy(&csupply->supply, supply, sizeof(*supply));
+ csupply->supply.name = kstrdup_const(supply->name, GFP_KERNEL);
+ constraint->private = csupply;
+
+ return 0;
+
+remove_voltage:
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0)
+ regulator_set_voltage(csupply->reg, 0, INT_MAX);
+free_regulator:
+ regulator_put(csupply->reg);
+free:
+ kfree(csupply);
+
+ return ret;
+}
+
+void constraint_supply_remove(struct constraint *constraint)
+{
+ struct constraint_supply *csupply = constraint->private;
+ struct dev_boot_constraint_supply_info *supply = &csupply->supply;
+ struct device *dev = constraint->cdev->dev;
+ int ret;
+
+ kfree_const(supply->name);
+
+ ret = regulator_disable(csupply->reg);
+ if (ret)
+ dev_err(dev, "regulator_disable failed (%d)\n", ret);
+
+ if (supply->u_volt_min != 0 && supply->u_volt_max != 0) {
+ ret = regulator_set_voltage(csupply->reg, 0, INT_MAX);
+ if (ret)
+ dev_err(dev, "regulator_set_voltage failed (%d)\n",
+ ret);
+ }
+
+ regulator_put(csupply->reg);
+ kfree(csupply);
+}
@@ -15,7 +15,13 @@
struct device;
enum dev_boot_constraint_type {
- DEV_BOOT_CONSTRAINT_NONE,
+ DEV_BOOT_CONSTRAINT_SUPPLY,
+};
+
+struct dev_boot_constraint_supply_info {
+ const char *name;
+ unsigned int u_volt_min;
+ unsigned int u_volt_max;
};
struct dev_boot_constraint {