[PATCH V3 3/4] regulator: pv88080: Update Regulator driver for MFD support

From: Eric Jeong
Date: Thu Nov 17 2016 - 20:00:31 EST



From: Eric Jeong <eric.jeong.opensource@xxxxxxxxxxx>

This change convert from using struct i2c_clinet
to using struct platform_device for MFD structure.
And, the declaration of of_device_id and regmap_config
are also move to MFD driver.

The configuration for MASK registers is moved
to MFD core.

Kconfig is updated to reflect support for PV88080 regulator.

Signed-off-by: Eric Jeong <eric.jeong.opensource@xxxxxxxxxxx>

---
This patch applies against linux-next and next-20161117

Hi,

The existing PV88080 regulstor driver is updated to support
MFD structure by adding GPIO function.
Most of changes are related with MFD structure support.

Change since PATCH V2
- Fix regression in config and driver
- Change IRQ name.

Change since PATCH V1
- Patch separated from PATCH V1

Regards,
Eric Jeong, Dialog Semiconductor Ltd.


drivers/regulator/Kconfig | 9 +-
drivers/regulator/pv88080-regulator.c | 185 +++++++++++----------------------
drivers/regulator/pv88080-regulator.h | 118 ---------------------
3 files changed, 66 insertions(+), 246 deletions(-)
delete mode 100644 drivers/regulator/pv88080-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 936f7cc..ea89653 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -577,10 +577,13 @@ config REGULATOR_PV88060

config REGULATOR_PV88080
tristate "Powerventure Semiconductor PV88080 regulator"
- depends on I2C
- select REGMAP_I2C
+ depends on MFD_PV88080
help
- Say y here to support the buck convertors on PV88080
+ Say y here to support the BUCKs regulators found on
+ PV88080 PMICs.
+
+ This driver can also be built as a module. If so, the module
+ will be called pv88080-regulator.

config REGULATOR_PV88090
tristate "Powerventure Semiconductor PV88090 regulator"
diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c
index 954a20e..eb9024d 100644
--- a/drivers/regulator/pv88080-regulator.c
+++ b/drivers/regulator/pv88080-regulator.c
@@ -14,8 +14,8 @@
*/

#include <linux/err.h>
-#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -25,9 +25,8 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
-#include "pv88080-regulator.h"

-#define PV88080_MAX_REGULATORS 4
+#include <linux/mfd/pv88080.h>

/* PV88080 REGULATOR IDs */
enum {
@@ -38,11 +37,6 @@ enum {
PV88080_ID_HVBUCK,
};

-enum pv88080_types {
- TYPE_PV88080_AA,
- TYPE_PV88080_BA,
-};
-
struct pv88080_regulator {
struct regulator_desc desc;
/* Current limiting */
@@ -55,14 +49,6 @@ struct pv88080_regulator {
unsigned int conf5;
};

-struct pv88080 {
- struct device *dev;
- struct regmap *regmap;
- struct regulator_dev *rdev[PV88080_MAX_REGULATORS];
- unsigned long type;
- const struct pv88080_compatible_regmap *regmap_config;
-};
-
struct pv88080_buck_voltage {
int min_uV;
int max_uV;
@@ -93,9 +79,11 @@ struct pv88080_compatible_regmap {
int hvbuck_vsel_mask;
};

-static const struct regmap_config pv88080_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
+struct pv88080_regulators {
+ int virq;
+ struct pv88080 *pv88080;
+ struct regulator_dev *rdev[PV88080_MAX_REGULATORS];
+ const struct pv88080_compatible_regmap *regmap_config;
};

/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
@@ -211,16 +199,6 @@ struct pv88080_compatible_regmap {
.hvbuck_vsel_mask = PV88080_VHVBUCK_MASK,
};

-#ifdef CONFIG_OF
-static const struct of_device_id pv88080_dt_ids[] = {
- { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA },
- { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA },
- { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA },
- {},
-};
-MODULE_DEVICE_TABLE(of, pv88080_dt_ids);
-#endif
-
static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev)
{
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
@@ -372,9 +350,10 @@ static int pv88080_get_current_limit(struct regulator_dev *rdev)
PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000),
};

-static irqreturn_t pv88080_irq_handler(int irq, void *data)
+static irqreturn_t pv88080_vdd_overtemp_event(int irq, void *data)
{
- struct pv88080 *chip = data;
+ struct pv88080_regulators *regulators = data;
+ struct pv88080 *chip = regulators->pv88080;
int i, reg_val, err, ret = IRQ_NONE;

err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, &reg_val);
@@ -383,8 +362,9 @@ static irqreturn_t pv88080_irq_handler(int irq, void *data)

if (reg_val & PV88080_E_VDD_FLT) {
for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
- if (chip->rdev[i] != NULL) {
- regulator_notifier_call_chain(chip->rdev[i],
+ if (regulators->rdev[i] != NULL) {
+ regulator_notifier_call_chain(
+ regulators->rdev[i],
REGULATOR_EVENT_UNDER_VOLTAGE,
NULL);
}
@@ -400,8 +380,9 @@ static irqreturn_t pv88080_irq_handler(int irq, void *data)

if (reg_val & PV88080_E_OVER_TEMP) {
for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
- if (chip->rdev[i] != NULL) {
- regulator_notifier_call_chain(chip->rdev[i],
+ if (regulators->rdev[i] != NULL) {
+ regulator_notifier_call_chain(
+ regulators->rdev[i],
REGULATOR_EVENT_OVER_TEMP,
NULL);
}
@@ -425,94 +406,61 @@ static irqreturn_t pv88080_irq_handler(int irq, void *data)
/*
* I2C driver interface functions
*/
-static int pv88080_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int pv88080_regulator_probe(struct platform_device *pdev)
{
- struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
- struct pv88080 *chip;
+ struct regulator_init_data *init_data = dev_get_platdata(&pdev->dev);
+ struct pv88080 *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pv88080_regulators *regulators;
const struct pv88080_compatible_regmap *regmap_config;
- const struct of_device_id *match;
struct regulator_config config = { };
- int i, error, ret;
+ int i, ret, irq;
unsigned int conf2, conf5;

- chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL);
- if (!chip)
+ regulators = devm_kzalloc(&pdev->dev,
+ sizeof(struct pv88080_regulators), GFP_KERNEL);
+ if (!regulators)
return -ENOMEM;

- chip->dev = &i2c->dev;
- chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config);
- if (IS_ERR(chip->regmap)) {
- error = PTR_ERR(chip->regmap);
- dev_err(chip->dev, "Failed to allocate register map: %d\n",
- error);
- return error;
- }
+ platform_set_drvdata(pdev, regulators);

- if (i2c->dev.of_node) {
- match = of_match_node(pv88080_dt_ids, i2c->dev.of_node);
- if (!match) {
- dev_err(chip->dev, "Failed to get of_match_node\n");
- return -EINVAL;
- }
- chip->type = (unsigned long)match->data;
- } else {
- chip->type = id->driver_data;
+ irq = platform_get_irq_byname(pdev, "VDD_TEMP_FAULT");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ.\n");
+ return irq;
}

- i2c_set_clientdata(i2c, chip);
-
- if (i2c->irq != 0) {
- ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);
- if (ret < 0) {
- dev_err(chip->dev,
- "Failed to mask A reg: %d\n", ret);
- return ret;
- }
- ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);
- if (ret < 0) {
- dev_err(chip->dev,
- "Failed to mask B reg: %d\n", ret);
- return ret;
- }
- ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);
- if (ret < 0) {
- dev_err(chip->dev,
- "Failed to mask C reg: %d\n", ret);
- return ret;
- }
-
- ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
- pv88080_irq_handler,
- IRQF_TRIGGER_LOW|IRQF_ONESHOT,
- "pv88080", chip);
- if (ret != 0) {
- dev_err(chip->dev, "Failed to request IRQ: %d\n",
- i2c->irq);
+ regulators->virq = regmap_irq_get_virq(chip->irq_data, irq);
+ if (regulators->virq >= 0) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ regulators->virq, NULL,
+ pv88080_vdd_overtemp_event,
+ IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+ "VDD_TEMP_FAULT", regulators);
+ if (ret) {
+ dev_err(chip->dev, "Failed to request IRQ: %d\n", irq);
return ret;
}
+ }

- ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A,
- PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0);
- if (ret < 0) {
- dev_err(chip->dev,
- "Failed to update mask reg: %d\n", ret);
- return ret;
- }
- } else {
- dev_warn(chip->dev, "No IRQ configured\n");
+ ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A,
+ PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to update mask reg: %d\n", ret);
+ return ret;
}

switch (chip->type) {
case TYPE_PV88080_AA:
- chip->regmap_config = &pv88080_aa_regs;
+ regulators->regmap_config = &pv88080_aa_regs;
break;
case TYPE_PV88080_BA:
- chip->regmap_config = &pv88080_ba_regs;
+ regulators->regmap_config = &pv88080_ba_regs;
break;
}

- regmap_config = chip->regmap_config;
+ regulators->pv88080 = chip;
+ regmap_config = regulators->regmap_config;
config.dev = chip->dev;
config.regmap = chip->regmap;

@@ -564,12 +512,12 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
/(pv88080_regulator_info[i].desc.uV_step) + 1;

config.driver_data = (void *)&pv88080_regulator_info[i];
- chip->rdev[i] = devm_regulator_register(chip->dev,
+ regulators->rdev[i] = devm_regulator_register(chip->dev,
&pv88080_regulator_info[i].desc, &config);
- if (IS_ERR(chip->rdev[i])) {
+ if (IS_ERR(regulators->rdev[i])) {
dev_err(chip->dev,
"Failed to register PV88080 regulator\n");
- return PTR_ERR(chip->rdev[i]);
+ return PTR_ERR(regulators->rdev[i]);
}
}

@@ -582,40 +530,27 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask
= regmap_config->hvbuck_vsel_mask;

- /* Registeration for HVBUCK */
if (init_data)
config.init_data = &init_data[PV88080_ID_HVBUCK];

config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK];
- chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev,
+ regulators->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev,
&pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config);
- if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) {
+ if (IS_ERR(regulators->rdev[PV88080_ID_HVBUCK])) {
dev_err(chip->dev, "Failed to register PV88080 regulator\n");
- return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]);
+ return PTR_ERR(regulators->rdev[PV88080_ID_HVBUCK]);
}

return 0;
}
-
-static const struct i2c_device_id pv88080_i2c_id[] = {
- { "pv88080", TYPE_PV88080_AA },
- { "pv88080-aa", TYPE_PV88080_AA },
- { "pv88080-ba", TYPE_PV88080_BA },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id);
-
-static struct i2c_driver pv88080_regulator_driver = {
+static struct platform_driver pv88080_regulator_driver = {
.driver = {
- .name = "pv88080",
- .of_match_table = of_match_ptr(pv88080_dt_ids),
+ .name = "pv88080-regulator",
},
- .probe = pv88080_i2c_probe,
- .id_table = pv88080_i2c_id,
+ .probe = pv88080_regulator_probe,
};
+module_platform_driver(pv88080_regulator_driver);

-module_i2c_driver(pv88080_regulator_driver);
-
-MODULE_AUTHOR("James Ban <James.Ban.opensource@xxxxxxxxxxx>");
+MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@xxxxxxxxxxx>");
MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pv88080-regulator.h b/drivers/regulator/pv88080-regulator.h
deleted file mode 100644
index ae25ff3..0000000
--- a/drivers/regulator/pv88080-regulator.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * pv88080-regulator.h - Regulator definitions for PV88080
- * Copyright (C) 2016 Powerventure Semiconductor Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __PV88080_REGISTERS_H__
-#define __PV88080_REGISTERS_H__
-
-/* System Control and Event Registers */
-#define PV88080_REG_EVENT_A 0x04
-#define PV88080_REG_MASK_A 0x09
-#define PV88080_REG_MASK_B 0x0A
-#define PV88080_REG_MASK_C 0x0B
-
-/* Regulator Registers - rev. AA */
-#define PV88080AA_REG_HVBUCK_CONF1 0x2D
-#define PV88080AA_REG_HVBUCK_CONF2 0x2E
-#define PV88080AA_REG_BUCK1_CONF0 0x27
-#define PV88080AA_REG_BUCK1_CONF1 0x28
-#define PV88080AA_REG_BUCK1_CONF2 0x59
-#define PV88080AA_REG_BUCK1_CONF5 0x5C
-#define PV88080AA_REG_BUCK2_CONF0 0x29
-#define PV88080AA_REG_BUCK2_CONF1 0x2A
-#define PV88080AA_REG_BUCK2_CONF2 0x61
-#define PV88080AA_REG_BUCK2_CONF5 0x64
-#define PV88080AA_REG_BUCK3_CONF0 0x2B
-#define PV88080AA_REG_BUCK3_CONF1 0x2C
-#define PV88080AA_REG_BUCK3_CONF2 0x69
-#define PV88080AA_REG_BUCK3_CONF5 0x6C
-
-/* Regulator Registers - rev. BA */
-#define PV88080BA_REG_HVBUCK_CONF1 0x33
-#define PV88080BA_REG_HVBUCK_CONF2 0x34
-#define PV88080BA_REG_BUCK1_CONF0 0x2A
-#define PV88080BA_REG_BUCK1_CONF1 0x2C
-#define PV88080BA_REG_BUCK1_CONF2 0x5A
-#define PV88080BA_REG_BUCK1_CONF5 0x5D
-#define PV88080BA_REG_BUCK2_CONF0 0x2D
-#define PV88080BA_REG_BUCK2_CONF1 0x2F
-#define PV88080BA_REG_BUCK2_CONF2 0x63
-#define PV88080BA_REG_BUCK2_CONF5 0x66
-#define PV88080BA_REG_BUCK3_CONF0 0x30
-#define PV88080BA_REG_BUCK3_CONF1 0x32
-#define PV88080BA_REG_BUCK3_CONF2 0x6C
-#define PV88080BA_REG_BUCK3_CONF5 0x6F
-
-/* PV88080_REG_EVENT_A (addr=0x04) */
-#define PV88080_E_VDD_FLT 0x01
-#define PV88080_E_OVER_TEMP 0x02
-
-/* PV88080_REG_MASK_A (addr=0x09) */
-#define PV88080_M_VDD_FLT 0x01
-#define PV88080_M_OVER_TEMP 0x02
-
-/* PV88080_REG_BUCK1_CONF0 (addr=0x27|0x2A) */
-#define PV88080_BUCK1_EN 0x80
-#define PV88080_VBUCK1_MASK 0x7F
-
-/* PV88080_REG_BUCK2_CONF0 (addr=0x29|0x2D) */
-#define PV88080_BUCK2_EN 0x80
-#define PV88080_VBUCK2_MASK 0x7F
-
-/* PV88080_REG_BUCK3_CONF0 (addr=0x2B|0x30) */
-#define PV88080_BUCK3_EN 0x80
-#define PV88080_VBUCK3_MASK 0x7F
-
-/* PV88080_REG_BUCK1_CONF1 (addr=0x28|0x2C) */
-#define PV88080_BUCK1_ILIM_SHIFT 2
-#define PV88080_BUCK1_ILIM_MASK 0x0C
-#define PV88080_BUCK1_MODE_MASK 0x03
-
-/* PV88080_REG_BUCK2_CONF1 (addr=0x2A|0x2F) */
-#define PV88080_BUCK2_ILIM_SHIFT 2
-#define PV88080_BUCK2_ILIM_MASK 0x0C
-#define PV88080_BUCK2_MODE_MASK 0x03
-
-/* PV88080_REG_BUCK3_CONF1 (addr=0x2C|0x32) */
-#define PV88080_BUCK3_ILIM_SHIFT 2
-#define PV88080_BUCK3_ILIM_MASK 0x0C
-#define PV88080_BUCK3_MODE_MASK 0x03
-
-#define PV88080_BUCK_MODE_SLEEP 0x00
-#define PV88080_BUCK_MODE_AUTO 0x01
-#define PV88080_BUCK_MODE_SYNC 0x02
-
-/* PV88080_REG_HVBUCK_CONF1 (addr=0x2D|0x33) */
-#define PV88080_VHVBUCK_MASK 0xFF
-
-/* PV88080_REG_HVBUCK_CONF1 (addr=0x2E|0x34) */
-#define PV88080_HVBUCK_EN 0x01
-
-/* PV88080_REG_BUCK2_CONF2 (addr=0x61|0x63) */
-/* PV88080_REG_BUCK3_CONF2 (addr=0x69|0x6C) */
-#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
-#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
-
-#define PV88080_BUCK_VDAC_RANGE_1 0x00
-#define PV88080_BUCK_VDAC_RANGE_2 0x01
-
-/* PV88080_REG_BUCK2_CONF5 (addr=0x64|0x66) */
-/* PV88080_REG_BUCK3_CONF5 (addr=0x6C|0x6F) */
-#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
-#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
-
-#define PV88080_BUCK_VRANGE_GAIN_1 0x00
-#define PV88080_BUCK_VRANGE_GAIN_2 0x01
-
-#endif /* __PV88080_REGISTERS_H__ */
--
end-of-patch for PATCH V3