[RFC 2/3] regulator: fixed: Handle optional overcurrent pin

From: ahaslam
Date: Wed Oct 26 2016 - 15:01:12 EST


From: Axel Haslam <ahaslam@xxxxxxxxxxxx>

Fixed regulators (ex. TPS2087D) may have a over current pin that
is activated when an over current condition is detected. Consumers
may be interested to know about the status changes of this pin to
disable the regulator and notify framework layers or userspace.

Allow the fix regulator to take in an optional gpio pin to
send the event changes to the consumer.

Signed-off-by: Axel Haslam <ahaslam@xxxxxxxxxxxx>
---
drivers/regulator/fixed.c | 47 +++++++++++++++++++++++++++++++++++++++++
include/linux/regulator/fixed.h | 3 +++
2 files changed, 50 insertions(+)

diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a747..9937139 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -30,10 +30,14 @@
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/interrupt.h>

struct fixed_voltage_data {
struct regulator_desc desc;
struct regulator_dev *dev;
+ int oc_gpio;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
};


@@ -94,6 +98,22 @@ struct fixed_voltage_data {
return config;
}

+static irqreturn_t reg_fixed_overcurrent_irq(int irq, void *data)
+{
+ struct fixed_voltage_data *drvdata = data;
+ unsigned long event = REGULATOR_EVENT_OVER_CURRENT_CHANGE;
+ int oc_value;
+
+ oc_value = gpio_get_value_cansleep(drvdata->oc_gpio);
+ if (oc_value == drvdata->oc_high)
+ event |= REGULATOR_EVENT_OVER_CURRENT;
+
+ regulator_notifier_call_chain(drvdata->dev, event, NULL);
+
+ return IRQ_HANDLED;
+}
+
+
static struct regulator_ops fixed_voltage_ops = {
};

@@ -175,6 +195,33 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = pdev->dev.of_node;

+ if (config->has_oc_gpio && gpio_is_valid(config->oc_gpio)) {
+
+ ret = devm_gpio_request_one(&pdev->dev,
+ config->oc_gpio,
+ GPIOF_DIR_IN, "oc_gpio");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request gpio: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev,
+ gpio_to_irq(config->oc_gpio), NULL,
+ reg_fixed_overcurrent_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "over_current", drvdata);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed tp request irq: %d\n", ret);
+ return ret;
+ }
+ drvdata->oc_gpio = config->oc_gpio;
+ drvdata->oc_high = config->oc_high;
+ drvdata->has_oc_gpio = config->has_oc_gpio;
+ }
+
drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
&cfg);
if (IS_ERR(drvdata->dev)) {
diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h
index 48918be..79357be 100644
--- a/include/linux/regulator/fixed.h
+++ b/include/linux/regulator/fixed.h
@@ -50,10 +50,13 @@ struct fixed_voltage_config {
const char *input_supply;
int microvolts;
int gpio;
+ int oc_gpio;
unsigned startup_delay;
unsigned gpio_is_open_drain:1;
unsigned enable_high:1;
unsigned enabled_at_boot:1;
+ unsigned has_oc_gpio:1;
+ unsigned oc_high:1;
struct regulator_init_data *init_data;
};

--
1.9.1