2010-07-13 06:42:13

by Sundar R IYER

[permalink] [raw]
Subject: [PATCH 0/3] ab8500-mfd: add regulator support

From: Sundar R Iyer <[email protected]>

Sundar R Iyer (3):
ab8500-mfd: add regulator support to ab8500 mfd device
regulator: add support for regulators on the ab8500 MFD
ux500: add ab8500-regulators machine specific data

arch/arm/mach-ux500/Makefile | 1 +
arch/arm/mach-ux500/board-mop500-regulators.c | 214 +++++++++++++
drivers/mfd/ab8500-core.c | 4 +-
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/ab8500.c | 414 +++++++++++++++++++++++++
include/linux/mfd/ab8500.h | 6 +
include/linux/regulator/ab8500.h | 25 ++
8 files changed, 672 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/mach-ux500/board-mop500-regulators.c
create mode 100644 drivers/regulator/ab8500.c
create mode 100644 include/linux/regulator/ab8500.h


2010-07-13 06:24:27

by Sundar R IYER

[permalink] [raw]
Subject: [PATCH 1/3] ab8500-mfd: add regulator support to ab8500 mfd device

From: Sundar R Iyer <[email protected]>

Acked-by: Linus Walleij <[email protected]>
Acked-By: Mattias Wallin <[email protected]>
Acked-By: Bengt JONSSON <[email protected]>
Signed-off-by: Sundar R Iyer <[email protected]>
---
drivers/mfd/ab8500-core.c | 4 +++-
include/linux/mfd/ab8500.h | 6 ++++++
include/linux/regulator/ab8500.h | 25 +++++++++++++++++++++++++
3 files changed, 34 insertions(+), 1 deletions(-)
create mode 100644 include/linux/regulator/ab8500.h

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index f3d26fa..defa786 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ab8500.h>
+#include <linux/regulator/ab8500.h>

/*
* Interrupt register offsets
@@ -352,6 +353,7 @@ static struct mfd_cell ab8500_devs[] = {
{ .name = "ab8500-audio", },
{ .name = "ab8500-usb", },
{ .name = "ab8500-pwm", },
+ { .name = "ab8500-regulator", },
};

int __devinit ab8500_init(struct ab8500 *ab8500)
@@ -411,7 +413,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
goto out_removeirq;
}

- ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs,
+ ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
ab8500->irq_base);
if (ret)
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index b63ff3b..f5cec45 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -76,6 +76,8 @@
#define AB8500_NR_IRQS 104
#define AB8500_NUM_IRQ_REGS 13

+#define AB8500_NUM_REGULATORS 15
+
/**
* struct ab8500 - ab8500 internal structure
* @dev: parent device
@@ -108,14 +110,18 @@ struct ab8500 {
u8 oldmask[AB8500_NUM_IRQ_REGS];
};

+struct regulator_init_data;
+
/**
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500
+ * @regulator: machine-specific constraints for regulators
*/
struct ab8500_platform_data {
int irq_base;
void (*init) (struct ab8500 *);
+ struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
};

extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
new file mode 100644
index 0000000..f509877
--- /dev/null
+++ b/include/linux/regulator/ab8500.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <[email protected]> for ST-Ericsson
+ *
+ */
+
+#ifndef __LINUX_MFD_AB8500_REGULATOR_H
+#define __LINUX_MFD_AB8500_REGULATOR_H
+
+/* AB8500 regulators */
+#define AB8500_LDO_AUX1 0
+#define AB8500_LDO_AUX2 1
+#define AB8500_LDO_AUX3 2
+#define AB8500_LDO_INTCORE 3
+#define AB8500_LDO_TVOUT 4
+#define AB8500_LDO_AUDIO 5
+#define AB8500_LDO_ANAMIC1 6
+#define AB8500_LDO_ANAMIC2 7
+#define AB8500_LDO_DMIC 8
+#define AB8500_LDO_ANA 9
+
+#endif
--
1.7.0

2010-07-13 06:49:57

by Sundar R IYER

[permalink] [raw]
Subject: [PATCH 3/3] ux500: add ab8500-regulators machine specific data

From: Sundar R Iyer <[email protected]>

Acked-by: Linus Walleij <[email protected]>
Acked-By: Bengt JONSSON <[email protected]>
Signed-off-by: Sundar R Iyer <[email protected]>
---
arch/arm/mach-ux500/Makefile | 1 +
arch/arm/mach-ux500/board-mop500-regulators.c | 214 +++++++++++++++++++++++++
2 files changed, 215 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-ux500/board-mop500-regulators.c

diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 0753a69..311f996 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_AB8500_PRCMU_I2C) += ab8500-prcmu-i2c.o
+obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
new file mode 100644
index 0000000..8a10ad0
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <[email protected]>
+ *
+ * MOP500 board specific initialization for regulators
+ */
+#include <linux/kernel.h>
+#include <linux/regulator/machine.h>
+
+#define AB8500_VAUXN_LDO_MIN_VOLTAGE (1100000)
+#define AB8500_VAUXN_LDO_MAX_VOLTAGE (3300000)
+
+static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
+ { .dev = NULL, .supply = "vaux1", },
+};
+
+struct regulator_init_data ab8500_vaux1_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux1",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
+};
+
+static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
+ { .dev = NULL, .supply = "vaux2", },
+};
+
+struct regulator_init_data ab8500_vaux2_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux2",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
+};
+
+static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ { .dev = NULL, .supply = "vaux3", },
+};
+
+struct regulator_init_data ab8500_vaux3_regulator = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaux3",
+ .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
+};
+
+/* supply for tvout, gpadc, TVOUT LDO */
+#define AB8500_VTVOUT_LDO_MIN_VOLTAGE (1900000)
+#define AB8500_VTVOUT_LDO_MAX_VOLTAGE (2100000)
+
+static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
+ { .dev = NULL, .supply = "vtvout", },
+};
+
+struct regulator_init_data ab8500_vtvout_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vtvout",
+ .min_uV = AB8500_VTVOUT_LDO_MIN_VOLTAGE,
+ .max_uV = AB8500_VTVOUT_LDO_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
+ .consumer_supplies = ab8500_vtvout_consumers,
+};
+
+
+
+/* supply for ab8500-vaudio, VAUDIO LDO */
+#define AB8500_VAUDIO_REGULATOR_MIN_VOLTAGE (1925000)
+#define AB8500_VAUDIO_REGULATOR_MAX_VOLTAGE (2075000)
+
+static struct regulator_consumer_supply ab8500_vaudio_consumers[] = {
+ { .dev = NULL, .supply = "vaudio", },
+};
+
+struct regulator_init_data ab8500_vaudio_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vaudio",
+ .min_uV = AB8500_VAUDIO_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAUDIO_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaudio_consumers),
+ .consumer_supplies = ab8500_vaudio_consumers,
+};
+
+
+/* supply for v-anamic1 VAMic1-LDO */
+#define AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE (2000000)
+#define AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE (2100000)
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+ { .dev = NULL, .supply = "vana-mic1", },
+};
+
+struct regulator_init_data ab8500_vamic1_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vamic1",
+ .min_uV = AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+ .consumer_supplies = ab8500_vamic1_consumers,
+};
+
+
+/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+ { .dev = NULL, .supply = "vana-mic2", },
+};
+
+struct regulator_init_data ab8500_vamic2_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vamic2",
+ .min_uV = AB8500_VAMIC1_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VAMIC1_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+ .consumer_supplies = ab8500_vamic2_consumers,
+};
+
+/* supply for v-dmic, VDMIC LDO */
+#define AB8500_VDMIC_REGULATOR_MIN_VOLTAGE (1700000)
+#define AB8500_VDMIC_REGULATOR_MAX_VOLTAGE (1950000)
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+ { .dev = NULL, .supply = "vdig-mic", },
+};
+
+struct regulator_init_data ab8500_vdmic_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vdmic",
+ .min_uV = AB8500_VDMIC_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VDMIC_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+ .consumer_supplies = ab8500_vdmic_consumers,
+};
+
+/* supply for v-intcore12, VINTCORE12 LDO */
+#define AB8500_VINTCORE_REGULATOR_MIN_VOLTAGE (1200000)
+#define AB8500_VINTCORE_REGULATOR_MAX_VOLTAGE (1350000)
+
+static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
+ { .dev = NULL, .supply = "vintcore", },
+};
+
+struct regulator_init_data ab8500_vintcore_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vintcore",
+ .min_uV = AB8500_VINTCORE_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VINTCORE_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
+};
+
+/* supply for U8500 CSI/DSI, VANA LDO */
+#define AB8500_VANA_REGULATOR_MIN_VOLTAGE (0)
+#define AB8500_VANA_REGULATOR_MAX_VOLTAGE (1200000)
+
+static struct regulator_consumer_supply ab8500_vana_consumers[] = {
+ { .dev = NULL, .supply = "vana", },
+};
+
+struct regulator_init_data ab8500_vana_init = {
+ .supply_regulator_dev = NULL,
+ .constraints = {
+ .name = "ab8500-vana",
+ .min_uV = AB8500_VANA_REGULATOR_MIN_VOLTAGE,
+ .max_uV = AB8500_VANA_REGULATOR_MAX_VOLTAGE,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
+};
+
--
1.7.0

2010-07-13 06:50:31

by Sundar R IYER

[permalink] [raw]
Subject: [PATCH 2/3] regulator: add support for regulators on the ab8500 MFD

From: Sundar R Iyer <[email protected]>

Acked-by: Linus Walleij <[email protected]>
Acked-By: Bengt JONSSON <[email protected]>
Signed-off-by: Sundar R Iyer <[email protected]>
---
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/ab8500.c | 414 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 423 insertions(+), 0 deletions(-)
create mode 100644 drivers/regulator/ab8500.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 7cd8a29..6c14afd 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -221,5 +221,13 @@ config REGULATOR_AD5398
help
This driver supports AD5398 and AD5821 current regulator chips.
If building into module, its name is ad5398.ko.
+
+config REGULATOR_AB8500
+ bool "ST-Ericsson AB8500 Power Regulators"
+ depends on AB8500_CORE
+ help
+ This driver supports the regulators found on the ST-Ericsson mixed
+ signal AB8500 PMIC
+
endif

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 74a4638..fc696c5 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -34,5 +34,6 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
+obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o

ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
new file mode 100644
index 0000000..e33d279
--- /dev/null
+++ b/drivers/regulator/ab8500.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <[email protected]>
+ *
+ * AB8500 peripheral regulators
+ *
+ * AB8500 supports the following regulators,
+ * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT,
+ * VAUX1/2/3, VANA
+ *
+ * for DB8500 cut 1.0 and previous versions of the silicon, all accesses
+ * to registers are through the DB8500 SPI. In cut 1.1 onwards, these
+ * accesses are through the DB8500 APE_I2C
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/ab8500.h>
+
+/**
+ * struct ab8500_regulator_info - ab8500 regulator information
+ * @desc: regulator description
+ * @ab8500: ab8500 parent
+ * @regulator_dev: regulator device
+ * @max_uV: maximum voltage (for variable voltage supplies)
+ * @min_uV: minimum voltage (for variable voltage supplies)
+ * @fixed_uV: typical voltage (for fixed voltage supplies)
+ * @update_reg: register to control on/off
+ * @mask: mask to enable/disable regulator
+ * @enable: enable bits to enable the regulator
+ * @voltage_reg: register to control regulator voltage
+ * @voltage_mask: mask to control regulator voltage
+ * @typical_voltages: typical supported voltage table
+ * @voltages_len: number of supported voltages for the regulator
+ */
+struct ab8500_regulator_info {
+ struct regulator_desc desc;
+ struct ab8500 *ab8500;
+ struct regulator_dev *regulator;
+ int max_uV;
+ int min_uV;
+ int fixed_uV;
+ int update_reg;
+ int mask;
+ int enable;
+ int voltage_reg;
+ int voltage_mask;
+ int const *typical_voltages;
+ int voltages_len;
+};
+
+/* voltage tables for the vauxn/vintcore supplies */
+static const int ldo_vauxn_voltages[] = {
+ 1100000,
+ 1200000,
+ 1300000,
+ 1400000,
+ 1500000,
+ 1800000,
+ 1850000,
+ 1900000,
+ 2500000,
+ 2650000,
+ 2700000,
+ 2750000,
+ 2800000,
+ 2900000,
+ 3000000,
+ 3300000,
+};
+
+static const int ldo_vintcore_voltages[] = {
+ 1200000,
+ 1225000,
+ 1250000,
+ 1275000,
+ 1300000,
+ 1325000,
+ 1350000,
+};
+
+static int ab8500_regulator_enable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = ab8500_set_bits(info->ab8500, info->update_reg,
+ info->mask, info->enable);
+ if (ret < 0)
+ dev_dbg(rdev_get_dev(rdev),
+ "couldnt set enable bits for regulator\n");
+ return ret;
+}
+
+static int ab8500_regulator_disable(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = ab8500_set_bits(info->ab8500, info->update_reg,
+ info->mask, 0x0);
+ if (ret < 0)
+ dev_dbg(rdev_get_dev(rdev),
+ "couldnt set disable bits for regulator\n");
+ return ret;
+}
+
+static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = ab8500_read(info->ab8500, info->update_reg);
+ if (ret < 0)
+ dev_dbg(rdev_get_dev(rdev),
+ "couldnt read 0x%x register\n", info->update_reg);
+
+ if (ret & info->mask)
+ return true;
+ else
+ return false;
+}
+
+static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ if (selector > info->voltages_len)
+ return -EINVAL;
+
+ return info->typical_voltages[selector];
+}
+
+static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ ret = ab8500_read(info->ab8500, info->voltage_reg);
+ if (ret < 0)
+ dev_dbg(rdev_get_dev(rdev),
+ "couldnt read voltage reg for regulator\n");
+
+ /* vintcore has a different layout */
+ if (regulator_id == AB8500_LDO_INTCORE)
+ ret = info->typical_voltages[(ret & info->voltage_mask) >> 0x3];
+ else
+ ret = info->typical_voltages[(ret & info->voltage_mask)];
+
+ return ret;
+}
+
+static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int i;
+
+ /* check the supported voltage */
+ for (i = 0; i < info->voltages_len; i++) {
+ if ((info->typical_voltages[i] >= min_uV) &&
+ (info->typical_voltages[i] <= max_uV))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int regulator_id, ret;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* get the appropriate voltages within the range */
+ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+ if (ret < 0) {
+ dev_dbg(rdev_get_dev(rdev),
+ "coudlnt get best voltage for regulator\n");
+ }
+
+ /* set the registers for the request */
+ ret = ab8500_set_bits(info->ab8500, info->voltage_reg,
+ info->voltage_mask, ret);
+ if (ret < 0) {
+ dev_dbg(rdev_get_dev(rdev),
+ "couldnt set voltage reg for regulator\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct regulator_ops ab8500_regulator_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_voltage = ab8500_regulator_get_voltage,
+ .set_voltage = ab8500_regulator_set_voltage,
+ .list_voltage = ab8500_list_voltage,
+};
+
+static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
+{
+ int regulator_id;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= AB8500_NUM_REGULATORS)
+ return -EINVAL;
+
+ return info->fixed_uV;
+}
+
+static struct regulator_ops ab8500_ldo_fixed_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_voltage = ab8500_fixed_get_voltage,
+};
+
+#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable, \
+ volt_reg, volt_mask, voltages, \
+ len_volts) \
+{ \
+ .desc = { \
+ .name = "LDO-" #_id, \
+ .ops = &ab8500_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AB8500_LDO_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .update_reg = reg, \
+ .mask = reg_mask, \
+ .enable = reg_enable, \
+ .voltage_reg = volt_reg, \
+ .voltage_mask = volt_mask, \
+ .typical_voltages = voltages, \
+ .voltages_len = len_volts, \
+}
+
+#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask, \
+ reg_enable) \
+{ \
+ .desc = { \
+ .name = "LDO-" #_id, \
+ .ops = &ab8500_ldo_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = AB8500_LDO_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .fixed_uV = fixed * 1000, \
+ .update_reg = reg, \
+ .mask = reg_mask, \
+ .enable = reg_enable, \
+}
+
+static struct ab8500_regulator_info ab8500_regulator_info[] = {
+ /*
+ * Variable Voltage LDOs
+ * name, min uV, max uV, ctrl reg, reg mask, enable mask,
+ * volt ctrl reg, volt ctrl mask, volt table, num supported volts
+ */
+ AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf,
+ ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+ AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf,
+ ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+ AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf,
+ ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+ AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38,
+ ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
+
+ /*
+ * Fixed Voltage LDOs
+ * name, o/p uV, ctrl reg, enable, disable
+ */
+ AB8500_FIXED_LDO(TVOUT, 2000, 0x0380, 0x2, 0x2),
+ AB8500_FIXED_LDO(AUDIO, 2000, 0x0383, 0x2, 0x2),
+ AB8500_FIXED_LDO(ANAMIC1, 2050, 0x0383, 0x4, 0x4),
+ AB8500_FIXED_LDO(ANAMIC2, 2050, 0x0383, 0x8, 0x8),
+ AB8500_FIXED_LDO(DMIC, 1800, 0x0383, 0x10, 0x10),
+ AB8500_FIXED_LDO(ANA, 1200, 0x0383, 0xc, 0x4),
+};
+
+static inline struct ab8500_regulator_info *find_regulator_info(int id)
+{
+ struct ab8500_regulator_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ info = &ab8500_regulator_info[i];
+ if (info->desc.id == id)
+ return info;
+ }
+ return NULL;
+}
+
+static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+ int i, err;
+
+ if (!ab8500) {
+ dev_err(&pdev->dev, "null mfd parent\n");
+ return -EINVAL;
+ }
+
+ /* register all regulators */
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ struct ab8500_regulator_info *info = NULL;
+
+ /* assign per-regulator data */
+ info = &ab8500_regulator_info[i];
+ info->ab8500 = ab8500;
+
+ info->regulator = regulator_register(&info->desc, &pdev->dev,
+ pdata->regulator[i], info);
+ if (IS_ERR(info->regulator)) {
+ err = PTR_ERR(info->regulator);
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ /* when we fail, un-register all earlier regulators */
+ i--;
+ while (i > 0) {
+ info = &ab8500_regulator_info[i];
+ regulator_unregister(info->regulator);
+ i--;
+ }
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ struct ab8500_regulator_info *info = NULL;
+ info = &ab8500_regulator_info[i];
+ regulator_unregister(info->regulator);
+ }
+
+ return 0;
+}
+
+static struct platform_driver ab8500_regulator_driver = {
+ .probe = ab8500_regulator_probe,
+ .remove = __devexit_p(ab8500_regulator_remove),
+ .driver = {
+ .name = "ab8500-regulator",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_regulator_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ab8500_regulator_driver);
+ if (ret != 0)
+ pr_err("Failed to register ab8500 regulator: %d\n", ret);
+
+ return ret;
+}
+subsys_initcall(ab8500_regulator_init);
+
+static void __exit ab8500_regulator_exit(void)
+{
+ platform_driver_unregister(&ab8500_regulator_driver);
+}
+module_exit(ab8500_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <[email protected]>");
+MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
+MODULE_ALIAS("platform:ab8500-regulator");
--
1.7.0

2010-07-13 09:49:41

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 1/3] ab8500-mfd: add regulator support to ab8500 mfd device

On Tue, Jul 13, 2010 at 11:51:28AM +0530, Sundar Iyer wrote:
> From: Sundar R Iyer <[email protected]>

Acked-by: Mark Brown <[email protected]>

2010-07-13 09:55:59

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 2/3] regulator: add support for regulators on the ab8500 MFD

On Tue, Jul 13, 2010 at 11:51:29AM +0530, Sundar Iyer wrote:

> + * @mask: mask to enable/disable regulator
> + * @enable: enable bits to enable the regulator

Presumably these two will always be identical?

> + * @typical_voltages: typical supported voltage table

Why typical - might the set of supported values change, and if they do
how will that be detected and handled?

> + ret = ab8500_read(info->ab8500, info->update_reg);
> + if (ret < 0)
> + dev_dbg(rdev_get_dev(rdev),
> + "couldnt read 0x%x register\n", info->update_reg);
> +
> + if (ret & info->mask)
> + return true;
> + else
> + return false;

This should return the error code if the read failed.

> +static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
> + int min_uV, int max_uV)
> +{
> + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
> + int i;
> +
> + /* check the supported voltage */
> + for (i = 0; i < info->voltages_len; i++) {
> + if ((info->typical_voltages[i] >= min_uV) &&
> + (info->typical_voltages[i] <= max_uV))
> + return i;

The indentation here is confusing - the second line of the if () is
aligned with the return statement not the first line.

> + /* get the appropriate voltages within the range */
> + ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
> + if (ret < 0) {
> + dev_dbg(rdev_get_dev(rdev),
> + "coudlnt get best voltage for regulator\n");
> + }

Should return an error here.

> + /* set the registers for the request */
> + ret = ab8500_set_bits(info->ab8500, info->voltage_reg,
> + info->voltage_mask, ret);
> + if (ret < 0) {
> + dev_dbg(rdev_get_dev(rdev),
> + "couldnt set voltage reg for regulator\n");
> + return -EINVAL;

Should return the error you got back from set_bits() to provide maximum
information to the caller (besides, this isn't an invalid value - it's
an I/O issue).

> +static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
> +{
> + int regulator_id;
> + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
> +
> + regulator_id = rdev_get_id(rdev);
> + if (regulator_id >= AB8500_NUM_REGULATORS)
> + return -EINVAL;
> +
> + return info->fixed_uV;
> +}
> +
> +static struct regulator_ops ab8500_ldo_fixed_ops = {
> + .enable = ab8500_regulator_enable,
> + .disable = ab8500_regulator_disable,
> + .is_enabled = ab8500_regulator_is_enabled,
> + .get_voltage = ab8500_fixed_get_voltage,
> +};

Should have list_voltage() support also ideally.

2010-07-13 10:00:17

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 3/3] ux500: add ab8500-regulators machine specific data

On Tue, Jul 13, 2010 at 11:51:30AM +0530, Sundar Iyer wrote:

> +static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
> + { .dev = NULL, .supply = "vaux1", },
> +};

All these supplies with NULL devices are bogus, supplies are in terms of
the device being supplied not the labels on the board. If you've got a
supply with no device and the name of the supply on either the regulator
or the board you're most likely doing it wrong. The only exception is
for supplies used in cpufreq since we don't have a struct device we can
use there.

> +struct regulator_init_data ab8500_vaux2_regulator = {
> + .supply_regulator_dev = NULL,
> + .constraints = {
> + .name = "ab8500-vaux2",
> + .min_uV = AB8500_VAUXN_LDO_MIN_VOLTAGE,
> + .max_uV = AB8500_VAUXN_LDO_MAX_VOLTAGE,

I'm not convinced that these #defines help anything, they're used in
exactly one place so don't add much to either legibility or ease of
maintinance.

2010-07-14 10:13:40

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 1/3] ab8500-mfd: add regulator support to ab8500 mfd device

On Tue, Jul 13, 2010 at 11:51:28AM +0530, Sundar Iyer wrote:
> From: Sundar R Iyer <[email protected]>
>
> Acked-by: Linus Walleij <[email protected]>
> Acked-By: Mattias Wallin <[email protected]>
> Acked-By: Bengt JONSSON <[email protected]>
> Signed-off-by: Sundar R Iyer <[email protected]>
Liam, I guess this should make it upstream through your regulator tree.

For the mfd part though:
Acked-by: Samuel Ortiz <[email protected]>

Cheers,
Samuel.


> ---
> drivers/mfd/ab8500-core.c | 4 +++-
> include/linux/mfd/ab8500.h | 6 ++++++
> include/linux/regulator/ab8500.h | 25 +++++++++++++++++++++++++
> 3 files changed, 34 insertions(+), 1 deletions(-)
> create mode 100644 include/linux/regulator/ab8500.h
>
> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
> index f3d26fa..defa786 100644
> --- a/drivers/mfd/ab8500-core.c
> +++ b/drivers/mfd/ab8500-core.c
> @@ -16,6 +16,7 @@
> #include <linux/platform_device.h>
> #include <linux/mfd/core.h>
> #include <linux/mfd/ab8500.h>
> +#include <linux/regulator/ab8500.h>
>
> /*
> * Interrupt register offsets
> @@ -352,6 +353,7 @@ static struct mfd_cell ab8500_devs[] = {
> { .name = "ab8500-audio", },
> { .name = "ab8500-usb", },
> { .name = "ab8500-pwm", },
> + { .name = "ab8500-regulator", },
> };
>
> int __devinit ab8500_init(struct ab8500 *ab8500)
> @@ -411,7 +413,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
> goto out_removeirq;
> }
>
> - ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs,
> + ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
> ARRAY_SIZE(ab8500_devs), NULL,
> ab8500->irq_base);
> if (ret)
> diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
> index b63ff3b..f5cec45 100644
> --- a/include/linux/mfd/ab8500.h
> +++ b/include/linux/mfd/ab8500.h
> @@ -76,6 +76,8 @@
> #define AB8500_NR_IRQS 104
> #define AB8500_NUM_IRQ_REGS 13
>
> +#define AB8500_NUM_REGULATORS 15
> +
> /**
> * struct ab8500 - ab8500 internal structure
> * @dev: parent device
> @@ -108,14 +110,18 @@ struct ab8500 {
> u8 oldmask[AB8500_NUM_IRQ_REGS];
> };
>
> +struct regulator_init_data;
> +
> /**
> * struct ab8500_platform_data - AB8500 platform data
> * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
> * @init: board-specific initialization after detection of ab8500
> + * @regulator: machine-specific constraints for regulators
> */
> struct ab8500_platform_data {
> int irq_base;
> void (*init) (struct ab8500 *);
> + struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
> };
>
> extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
> diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
> new file mode 100644
> index 0000000..f509877
> --- /dev/null
> +++ b/include/linux/regulator/ab8500.h
> @@ -0,0 +1,25 @@
> +/*
> + * Copyright (C) ST-Ericsson SA 2010
> + *
> + * License Terms: GNU General Public License v2
> + *
> + * Author: Sundar Iyer <[email protected]> for ST-Ericsson
> + *
> + */
> +
> +#ifndef __LINUX_MFD_AB8500_REGULATOR_H
> +#define __LINUX_MFD_AB8500_REGULATOR_H
> +
> +/* AB8500 regulators */
> +#define AB8500_LDO_AUX1 0
> +#define AB8500_LDO_AUX2 1
> +#define AB8500_LDO_AUX3 2
> +#define AB8500_LDO_INTCORE 3
> +#define AB8500_LDO_TVOUT 4
> +#define AB8500_LDO_AUDIO 5
> +#define AB8500_LDO_ANAMIC1 6
> +#define AB8500_LDO_ANAMIC2 7
> +#define AB8500_LDO_DMIC 8
> +#define AB8500_LDO_ANA 9
> +
> +#endif
> --
> 1.7.0
>

--
Intel Open Source Technology Centre
http://oss.intel.com/

2010-07-15 10:29:43

by Liam Girdwood

[permalink] [raw]
Subject: Re: [PATCH 1/3] ab8500-mfd: add regulator support to ab8500 mfd device

On Wed, 2010-07-14 at 12:13 +0200, Samuel Ortiz wrote:
> On Tue, Jul 13, 2010 at 11:51:28AM +0530, Sundar Iyer wrote:
> > From: Sundar R Iyer <[email protected]>
> >
> > Acked-by: Linus Walleij <[email protected]>
> > Acked-By: Mattias Wallin <[email protected]>
> > Acked-By: Bengt JONSSON <[email protected]>
> > Signed-off-by: Sundar R Iyer <[email protected]>
> Liam, I guess this should make it upstream through your regulator tree.
>
> For the mfd part though:
> Acked-by: Samuel Ortiz <[email protected]>
>
> Cheers,
> Samuel.

Applied.

Thanks

Liam
--
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk