* [PATCH] regulator: add MAX8907 driver
@ 2012-08-02 18:27 Stephen Warren
2012-08-04 10:19 ` Mark Brown
0 siblings, 1 reply; 4+ messages in thread
From: Stephen Warren @ 2012-08-02 18:27 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown
Cc: linux-kernel, Laxman Dewangan, Gyungoh Yoo, Stephen Warren
From: Gyungoh Yoo <jack.yoo@maxim-ic.com>
The MAX8907 is an I2C-based power-management IC containing voltage
regulators, a reset controller, a real-time clock, and a touch-screen
controller.
The original driver was written by:
* Gyungoh Yoo <jack.yoo@maxim-ic.com>
Various fixes and enhancements by:
* Jin Park <jinyoungp@nvidia.com>
* Tom Cherry <tcherry@nvidia.com>
* Prashant Gaikwad <pgaikwad@nvidia.com>
* Dan Willemsen <dwillemsen@nvidia.com>
* Laxman Dewangan <ldewangan@nvidia.com>
During upstreaming, I (swarren):
* Converted to regmap.
* Allowed probing from device tree.
* Reworked the regulator driver to be represented as a single device that
provides multiple regulators, rather than as a device per regulator. It
seems like this is more common?
* Added ability to specify supplies for each regulator.
* Renamed from max8907c->max8907, since the driver covers at least the
C and B revisions.
* Removed list_voltage/get_voltage from WLED regulator, since it's a
current regulator not a voltage regulator.
* General cleanup.
Signed-off-by: Gyungoh Yoo <jack.yoo@maxim-ic.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/max8907-regulator.c | 606 +++++++++++++++++++++++++++++++++
3 files changed, 615 insertions(+), 0 deletions(-)
create mode 100644 drivers/regulator/max8907-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc..1c6320c 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -172,6 +172,14 @@ config REGULATOR_MAX8660
This driver controls a Maxim 8660/8661 voltage output
regulator via I2C bus.
+config REGULATOR_MAX8907
+ tristate "Maxim 8907 voltage regulator"
+ depends on MFD_MAX8907
+ help
+ This driver controls a Maxim 8907 voltage output regulator
+ via I2C bus. The provided regulator is suitable for Tegra
+ chip to control Step-Down DC-DC and LDOs.
+
config REGULATOR_MAX8925
tristate "Maxim MAX8925 Power Management IC"
depends on MFD_MAX8925
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3342615..3a0dbc5 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
new file mode 100644
index 0000000..a244398
--- /dev/null
+++ b/drivers/regulator/max8907-regulator.c
@@ -0,0 +1,606 @@
+/*
+ * max8907-regulator.c -- support regulators in max8907
+ *
+ * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
+ * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Portions based on drivers/regulator/tps65910-regulator.c,
+ * Copyright 2010 Texas Instruments Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8907.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define MAX8907_II2RR_VERSION_MASK 0xF0
+#define MAX8907_II2RR_VERSION_REV_A 0x00
+#define MAX8907_II2RR_VERSION_REV_B 0x10
+#define MAX8907_II2RR_VERSION_REV_C 0x30
+
+struct max8907_regulator_info {
+ u32 min_uV;
+ u32 max_uV;
+ u32 step_uV;
+ u8 reg_base;
+ struct regulator_desc desc;
+};
+
+struct max8907_regulator {
+ struct max8907_regulator_info info[MAX8907_NUM_REGULATORS];
+ struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
+};
+
+#define REG_MBATT() \
+ { \
+ .desc = { \
+ .supply_name = "mbatt", \
+ .name = "MBATT", \
+ .id = MAX8907_MBATT, \
+ .ops = &max8907_mbatt_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define REG_LDO(ids, supply, base, min, max, step) \
+ { \
+ .min_uV = (min), \
+ .max_uV = (max), \
+ .step_uV = (step), \
+ .reg_base = (base), \
+ .desc = { \
+ .supply_name = supply, \
+ .name = #ids, \
+ .id = MAX8907_##ids, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &max8907_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define REG_FIXED(ids, supply, voltage) \
+ { \
+ .min_uV = (voltage), \
+ .max_uV = (voltage), \
+ .desc = { \
+ .supply_name = supply, \
+ .name = #ids, \
+ .id = MAX8907_##ids, \
+ .n_voltages = 1, \
+ .ops = &max8907_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define REG_OUT5V(ids, supply, base, voltage) \
+ { \
+ .min_uV = (voltage), \
+ .max_uV = (voltage), \
+ .reg_base = (base), \
+ .desc = { \
+ .supply_name = supply, \
+ .name = #ids, \
+ .id = MAX8907_##ids, \
+ .n_voltages = 1, \
+ .ops = &max8907_out5v_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define REG_BBAT(ids, supply, base, min, max, step) \
+ { \
+ .min_uV = (min), \
+ .max_uV = (max), \
+ .step_uV = (step), \
+ .reg_base = (base), \
+ .desc = { \
+ .supply_name = supply, \
+ .name = #ids, \
+ .id = MAX8907_##ids, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &max8907_bbat_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define REG_WLED(ids, supply, base, voltage) \
+ { \
+ .min_uV = (voltage), \
+ .max_uV = (voltage), \
+ .reg_base = (base), \
+ .desc = { \
+ .supply_name = supply, \
+ .name = #ids, \
+ .id = MAX8907_##ids, \
+ .n_voltages = 1, \
+ .ops = &max8907_wled_ops, \
+ .type = REGULATOR_CURRENT, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), 750000, 3900000, 50000)
+#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), 650000, 2225000, 25000)
+
+static int max8907_regulator_list_voltage(struct regulator_dev *dev,
+ unsigned index);
+static int max8907_regulator_ldo_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV,
+ unsigned *selector);
+static int max8907_regulator_bbat_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV,
+ unsigned *selector);
+static int max8907_regulator_ldo_get_voltage(struct regulator_dev *dev);
+static int max8907_regulator_fixed_get_voltage(struct regulator_dev *dev);
+static int max8907_regulator_bbat_get_voltage(struct regulator_dev *dev);
+static int max8907_regulator_wled_set_current_limit(struct regulator_dev *dev,
+ int min_uA, int max_uA);
+static int max8907_regulator_wled_get_current_limit(struct regulator_dev *dev);
+static int max8907_regulator_ldo_enable(struct regulator_dev *dev);
+static int max8907_regulator_out5v_enable(struct regulator_dev *dev);
+static int max8907_regulator_ldo_disable(struct regulator_dev *dev);
+static int max8907_regulator_out5v_disable(struct regulator_dev *dev);
+static int max8907_regulator_ldo_is_enabled(struct regulator_dev *dev);
+static int max8907_regulator_out5v_is_enabled(struct regulator_dev *dev);
+
+static struct regulator_ops max8907_mbatt_ops = {
+};
+
+static struct regulator_ops max8907_ldo_ops = {
+ .list_voltage = max8907_regulator_list_voltage,
+ .set_voltage = max8907_regulator_ldo_set_voltage,
+ .get_voltage = max8907_regulator_ldo_get_voltage,
+ .enable = max8907_regulator_ldo_enable,
+ .disable = max8907_regulator_ldo_disable,
+ .is_enabled = max8907_regulator_ldo_is_enabled,
+};
+
+static struct regulator_ops max8907_fixed_ops = {
+ .list_voltage = max8907_regulator_list_voltage,
+ .get_voltage = max8907_regulator_fixed_get_voltage,
+};
+
+static struct regulator_ops max8907_out5v_ops = {
+ .list_voltage = max8907_regulator_list_voltage,
+ .get_voltage = max8907_regulator_fixed_get_voltage,
+ .enable = max8907_regulator_out5v_enable,
+ .disable = max8907_regulator_out5v_disable,
+ .is_enabled = max8907_regulator_out5v_is_enabled,
+};
+
+static struct regulator_ops max8907_bbat_ops = {
+ .list_voltage = max8907_regulator_list_voltage,
+ .set_voltage = max8907_regulator_bbat_set_voltage,
+ .get_voltage = max8907_regulator_bbat_get_voltage,
+};
+
+static struct regulator_ops max8907_wled_ops = {
+ .set_current_limit = max8907_regulator_wled_set_current_limit,
+ .get_current_limit = max8907_regulator_wled_get_current_limit,
+};
+
+static struct max8907_regulator_info max8907_regulators[] = {
+ REG_MBATT(),
+ REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
+ REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
+ REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
+ LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
+ LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
+ LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
+ LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
+ LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
+ LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
+ LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
+ LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
+ LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
+ LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
+ LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
+ LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
+ LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
+ LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
+ LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
+ LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
+ LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
+ LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
+ LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
+ LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
+ REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
+ REG_OUT5V(OUT33V, "mbatt", MAX8907_REG_OUT33VEN, 3300000),
+ REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG, 2400000, 3000000, 200000),
+ REG_FIXED(SDBY, "MBATT", 1200000),
+ REG_FIXED(VRTC, "MBATT", 3300000),
+ REG_WLED(WLED, "lxw", MAX8907_REG_ILED_CNTL, 0),
+};
+
+static int max8907_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned index)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ return info->min_uV + info->step_uV * index;
+}
+
+static int max8907_regulator_ldo_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV,
+ unsigned *selector)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ int val;
+
+ if (min_uV < info->min_uV || max_uV > info->max_uV)
+ return -EDOM;
+
+ val = (min_uV - info->min_uV) / info->step_uV;
+ *selector = val;
+
+ return regmap_write(rdev->regmap, info->reg_base + MAX8907_VOUT, val);
+}
+
+static int max8907_regulator_bbat_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV,
+ unsigned *selector)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ int val;
+
+ if (min_uV < info->min_uV || max_uV > info->max_uV)
+ return -EDOM;
+
+ val = (min_uV - info->min_uV) / info->step_uV;
+ *selector = val;
+
+ return regmap_update_bits(rdev->regmap, info->reg_base,
+ MAX8907_MASK_VBBATTCV, val);
+}
+
+static int max8907_regulator_ldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int val;
+
+ regmap_read(rdev->regmap, info->reg_base + MAX8907_VOUT, &val);
+ return val * info->step_uV + info->min_uV;
+}
+
+static int max8907_regulator_fixed_get_voltage(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ return info->min_uV;
+}
+
+static int max8907_regulator_bbat_get_voltage(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int val;
+
+ regmap_read(rdev->regmap, info->reg_base, &val);
+ return (val & MAX8907_MASK_VBBATTCV) * info->step_uV + info->min_uV;
+}
+
+static int max8907_regulator_wled_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ if (min_uA > 25500)
+ return -EDOM;
+
+ return regmap_write(rdev->regmap, info->reg_base, min_uA / 100);
+}
+
+static int max8907_regulator_wled_get_current_limit(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int val;
+
+ regmap_read(rdev->regmap, info->reg_base, &val);
+ return val * 100;
+}
+
+static int max8907_regulator_ldo_enable(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int reg = MAX8907_MASK_LDO_EN | MAX8907_MASK_LDO_SEQ;
+
+ return regmap_update_bits(rdev->regmap, info->reg_base + MAX8907_CTL,
+ reg, reg);
+}
+
+static int max8907_regulator_out5v_enable(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ return regmap_update_bits(rdev->regmap, info->reg_base,
+ MAX8907_MASK_OUT5V_VINEN |
+ MAX8907_MASK_OUT5V_ENSRC |
+ MAX8907_MASK_OUT5V_EN,
+ MAX8907_MASK_OUT5V_ENSRC |
+ MAX8907_MASK_OUT5V_EN);
+}
+
+static int max8907_regulator_ldo_disable(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ return regmap_update_bits(rdev->regmap, info->reg_base + MAX8907_CTL,
+ MAX8907_MASK_LDO_EN | MAX8907_MASK_LDO_SEQ,
+ MAX8907_MASK_LDO_SEQ);
+}
+
+static int max8907_regulator_out5v_disable(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+
+ return regmap_update_bits(rdev->regmap, info->reg_base,
+ MAX8907_MASK_OUT5V_VINEN |
+ MAX8907_MASK_OUT5V_ENSRC |
+ MAX8907_MASK_OUT5V_EN,
+ MAX8907_MASK_OUT5V_ENSRC);
+}
+
+static int max8907_regulator_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->reg_base + MAX8907_CTL, &val);
+ if (ret < 0)
+ return -EDOM;
+
+ return (val & MAX8907_MASK_LDO_EN) || !(val & MAX8907_MASK_LDO_SEQ);
+}
+
+static int max8907_regulator_out5v_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ const struct max8907_regulator_info *info = &pmic->info[id];
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, info->reg_base, &val);
+ if (ret < 0)
+ return -EDOM;
+
+ if ((val &
+ (MAX8907_MASK_OUT5V_VINEN | MAX8907_MASK_OUT5V_ENSRC |
+ MAX8907_MASK_OUT5V_EN))
+ == MAX8907_MASK_OUT5V_ENSRC)
+ return 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+
+#define MATCH(_name, _id) \
+ { \
+ .name = #_name, \
+ .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
+ }
+
+static struct of_regulator_match max8907_matches[] = {
+ MATCH(mbatt, MBATT),
+ MATCH(sd1, SD1),
+ MATCH(sd2, SD2),
+ MATCH(sd3, SD3),
+ MATCH(ldo1, LDO1),
+ MATCH(ldo2, LDO2),
+ MATCH(ldo3, LDO3),
+ MATCH(ldo4, LDO4),
+ MATCH(ldo5, LDO5),
+ MATCH(ldo6, LDO6),
+ MATCH(ldo7, LDO7),
+ MATCH(ldo8, LDO8),
+ MATCH(ldo9, LDO9),
+ MATCH(ldo10, LDO10),
+ MATCH(ldo11, LDO11),
+ MATCH(ldo12, LDO12),
+ MATCH(ldo13, LDO13),
+ MATCH(ldo14, LDO14),
+ MATCH(ldo15, LDO15),
+ MATCH(ldo16, LDO16),
+ MATCH(ldo17, LDO17),
+ MATCH(ldo18, LDO18),
+ MATCH(ldo19, LDO19),
+ MATCH(ldo20, LDO20),
+ MATCH(out5v, OUT5V),
+ MATCH(out33v, OUT33V),
+ MATCH(bbat, BBAT),
+ MATCH(sdby, SDBY),
+ MATCH(vrtc, VRTC),
+ MATCH(wled, WLED),
+};
+
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ int ret;
+
+ if (!pdev->dev.parent->of_node)
+ return 0;
+
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulators node not found\n");
+ return -EINVAL;
+ }
+
+ ret = of_regulator_match(pdev->dev.parent, regulators,
+ max8907_matches,
+ ARRAY_SIZE(max8907_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+static __devinit int max8907_regulator_probe(struct platform_device *pdev)
+{
+ struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
+ struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
+ int ret;
+ struct max8907_regulator *pmic;
+ unsigned int version;
+ int i;
+ struct regulator_config config = {};
+ struct regulator_init_data *idata;
+ const char *mbatt_rail_name = NULL;
+
+ ret = max8907_regulator_parse_dt(pdev);
+ if (ret)
+ return ret;
+
+ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic) {
+ dev_err(&pdev->dev, "Failed to alloc pmic\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, pmic);
+
+ memcpy(pmic->info, max8907_regulators, sizeof(pmic->info));
+
+ /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
+ regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &version);
+ if ((version & MAX8907_II2RR_VERSION_MASK) ==
+ MAX8907_II2RR_VERSION_REV_B) {
+ pmic->info[MAX8907_SD1].min_uV = 637500;
+ pmic->info[MAX8907_SD1].max_uV = 1425000;
+ pmic->info[MAX8907_SD1].step_uV = 12500;
+ }
+
+ for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+ config.dev = pdev->dev.parent;
+ if (pdata)
+ idata = pdata->init_data[i];
+ else
+ idata = max8907_matches[i].init_data;
+ config.init_data = idata;
+ config.driver_data = pmic;
+ config.regmap = max8907->regmap_gen;
+ config.of_node = max8907_matches[i].of_node;
+
+ switch (pmic->info[i].desc.id) {
+ case MAX8907_MBATT:
+ mbatt_rail_name = idata->constraints.name;
+ break;
+ case MAX8907_BBAT:
+ case MAX8907_SDBY:
+ case MAX8907_VRTC:
+ idata->supply_regulator = mbatt_rail_name;
+ break;
+ }
+
+ pmic->rdev[i] = regulator_register(&pmic->info[i].desc,
+ &config);
+ if (IS_ERR(pmic->rdev[i])) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ pmic->info[i].desc.name);
+ ret = PTR_ERR(pmic->rdev[i]);
+ goto err_unregister_regulator;
+ }
+ }
+
+ return 0;
+
+err_unregister_regulator:
+ while (--i >= 0)
+ regulator_unregister(pmic->rdev[i]);
+ return ret;
+}
+
+static __devexit int max8907_regulator_remove(struct platform_device *pdev)
+{
+ struct max8907_regulator *pmic;
+ int i;
+
+ for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
+ regulator_unregister(pmic->rdev[i]);
+
+ return 0;
+}
+
+static struct platform_driver max8907_regulator_driver = {
+ .driver = {
+ .name = "max8907-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8907_regulator_probe,
+ .remove = __devexit_p(max8907_regulator_remove),
+};
+
+static int __init max8907_regulator_init(void)
+{
+ return platform_driver_register(&max8907_regulator_driver);
+}
+
+subsys_initcall(max8907_regulator_init);
+
+static void __exit max8907_reg_exit(void)
+{
+ platform_driver_unregister(&max8907_regulator_driver);
+}
+
+module_exit(max8907_reg_exit);
+
+MODULE_DESCRIPTION("MAX8907 regulator driver");
+MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
+MODULE_LICENSE("GPL v2");
--
1.7.0.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] regulator: add MAX8907 driver
2012-08-02 18:27 [PATCH] regulator: add MAX8907 driver Stephen Warren
@ 2012-08-04 10:19 ` Mark Brown
2012-08-06 21:22 ` Stephen Warren
0 siblings, 1 reply; 4+ messages in thread
From: Mark Brown @ 2012-08-04 10:19 UTC (permalink / raw)
To: Stephen Warren
Cc: Liam Girdwood, linux-kernel, Laxman Dewangan, Gyungoh Yoo,
Stephen Warren
On Thu, Aug 02, 2012 at 12:27:13PM -0600, Stephen Warren wrote:
> The MAX8907 is an I2C-based power-management IC containing voltage
> regulators, a reset controller, a real-time clock, and a touch-screen
> controller.
> * Reworked the regulator driver to be represented as a single device that
> provides multiple regulators, rather than as a device per regulator. It
> seems like this is more common?
This is mostly a reflection of the poor reuse available with most
hardware. If you've got a bunch of regulators which can usefully
be instantiated and work out where they are by just getting a
register range or two, and especially if you've got a bunch of PMICs
with different arrangements of these things, then it's useful to
split into multiple drivers. If each regulator needs a bunch of custom
data then there's not much point.
> +static int max8907_regulator_list_voltage(struct regulator_dev *rdev,
> + unsigned index)
> +{
> + struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
> + int id = rdev_get_id(rdev);
> + const struct max8907_regulator_info *info = &pmic->info[id];
> +
> + return info->min_uV + info->step_uV * index;
> +}
regulator_list_voltage_linear().
> +static int max8907_regulator_ldo_set_voltage(struct regulator_dev *rdev,
> + int min_uV, int max_uV,
> + unsigned *selector)
Should use regulator_set_voltage_sel_regmap() and
regulator_map_voltage_linear().
> +static int max8907_regulator_bbat_set_voltage(struct regulator_dev *rdev,
> + int min_uV, int max_uV,
> + unsigned *selector)
Similarly for this regulator, use a linear mapping.
> +static int max8907_regulator_fixed_get_voltage(struct regulator_dev *rdev)
This one too.
> +static int max8907_regulator_wled_set_current_limit(struct regulator_dev *rdev,
> + int min_uA, int max_uA)
I'm really not convinced it makes much sense to represent the backlight
driver current regulators as regulators, they only get used as part of
the backlight and are usually tightly coupled to their boosts.
> +static int max8907_regulator_ldo_enable(struct regulator_dev *rdev)
> +{
> + struct max8907_regulator *pmic = rdev_get_drvdata(rdev);
> + int id = rdev_get_id(rdev);
> + const struct max8907_regulator_info *info = &pmic->info[id];
> + unsigned int reg = MAX8907_MASK_LDO_EN | MAX8907_MASK_LDO_SEQ;
> +
> + return regmap_update_bits(rdev->regmap, info->reg_base + MAX8907_CTL,
> + reg, reg);
regulator_enable_regmap() and friends (and similarly for a bunch of the
others).
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] regulator: add MAX8907 driver
2012-08-04 10:19 ` Mark Brown
@ 2012-08-06 21:22 ` Stephen Warren
2012-08-06 21:47 ` Mark Brown
0 siblings, 1 reply; 4+ messages in thread
From: Stephen Warren @ 2012-08-06 21:22 UTC (permalink / raw)
To: Mark Brown
Cc: Liam Girdwood, linux-kernel, Laxman Dewangan, Gyungoh Yoo,
Stephen Warren
On 08/04/2012 04:19 AM, Mark Brown wrote:
> On Thu, Aug 02, 2012 at 12:27:13PM -0600, Stephen Warren wrote:
>
>> The MAX8907 is an I2C-based power-management IC containing voltage
>> regulators, a reset controller, a real-time clock, and a touch-screen
>> controller.
>> +static int max8907_regulator_wled_set_current_limit(struct regulator_dev *rdev,
>> + int min_uA, int max_uA)
>
> I'm really not convinced it makes much sense to represent the backlight
> driver current regulators as regulators, they only get used as part of
> the backlight and are usually tightly coupled to their boosts.
So you mean just completely remove any reference to WLED from the
driver? There is a register to configure the current limit - do you not
expect anything to ever need to set that in the kernel; do you expect
the HW default to be correct, or the bootloader to set the desired value?
Thanks for the other parts of the review.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] regulator: add MAX8907 driver
2012-08-06 21:22 ` Stephen Warren
@ 2012-08-06 21:47 ` Mark Brown
0 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2012-08-06 21:47 UTC (permalink / raw)
To: Stephen Warren
Cc: Liam Girdwood, linux-kernel, Laxman Dewangan, Gyungoh Yoo,
Stephen Warren
On Mon, Aug 06, 2012 at 03:22:17PM -0600, Stephen Warren wrote:
> On 08/04/2012 04:19 AM, Mark Brown wrote:
> > I'm really not convinced it makes much sense to represent the backlight
> > driver current regulators as regulators, they only get used as part of
> > the backlight and are usually tightly coupled to their boosts.
> So you mean just completely remove any reference to WLED from the
> driver? There is a register to configure the current limit - do you not
> expect anything to ever need to set that in the kernel; do you expect
> the HW default to be correct, or the bootloader to set the desired value?
I'd expect it to be configured as part of configuring the overall
backlight, for an actual current regulator you're not setting a current
limit but rather a current which usually translates directly into a
brightness. As I say this will usually be done in conjunction with a
boost regulator.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-08-06 21:47 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-02 18:27 [PATCH] regulator: add MAX8907 driver Stephen Warren
2012-08-04 10:19 ` Mark Brown
2012-08-06 21:22 ` Stephen Warren
2012-08-06 21:47 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox