lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-id: <067801cd4d45$a743e820$f5cbb860$@com>
Date:	Mon, 18 Jun 2012 20:29:41 +0900
From:	Sangbeom Kim <sbkim73@...sung.com>
To:	'Mark Brown' <broonie@...nsource.wolfsonmicro.com>,
	sameo@...ux.intel.com
Cc:	'Liam Girdwood' <lrg@...com>, linux-kernel@...r.kernel.org
Subject: [PATCH 6/7] regualtor: Add samsung s2mps11 regulator driver

This patch add Samsung S2MPS11 regulator driver.
The S2MPS11 can support 10 Bucks and 38 LDOs and RTC.
Especially, S2MPS11 is designed for high performance
Samsung application processor.

Signed-off-by: Sangbeom Kim <sbkim73@...sung.com>
---
 drivers/regulator/Kconfig           |    8 +
 drivers/regulator/Makefile          |    1 +
 drivers/regulator/s2mps11.c         |  767 +++++++++++++++++++++++++++++++++++
 drivers/regulator/s5m8767.c         |    6 -
 include/linux/mfd/samsung/core.h    |   15 +
 include/linux/mfd/samsung/s2mps11.h |  179 ++++++++
 6 files changed, 970 insertions(+), 6 deletions(-)
 create mode 100644 drivers/regulator/s2mps11.c
 create mode 100644 include/linux/mfd/samsung/s2mps11.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 196aaae..afa1e11 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -241,6 +241,14 @@ config REGULATOR_RC5T583
 	  through regulator interface. The device supports multiple DCDC/LDO
 	  outputs which can be controlled by i2c communication.
 
+config REGULATOR_S2MPS11
+	tristate "Samsung S2MPS11 voltage regulator"
+	depends on MFD_SEC_CORE
+	help
+	 This driver supports a Samsung S2MPS11 voltage output regulator
+	 via I2C bus. S2MPS11 is comprised of high efficient Buck converters
+	 including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
+
 config REGULATOR_S5M8767
 	tristate "Samsung S5M8767A voltage regulator"
 	depends on MFD_SEC_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d854453..3935514 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
new file mode 100644
index 0000000..05cb727
--- /dev/null
+++ b/drivers/regulator/s2mps11.c
@@ -0,0 +1,767 @@
+/*
+ * s2mps11.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  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.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mps11.h>
+
+struct s2mps11_info {
+	struct device *dev;
+	struct sec_pmic_dev *iodev;
+	int num_regulators;
+	struct regulator_dev **rdev;
+	struct sec_opmode_data *opmode;
+
+	int ramp_delay2;
+	int ramp_delay34;
+	int ramp_delay5;
+	int ramp_delay16;
+	int ramp_delay7810;
+	int ramp_delay9;
+
+	bool buck6_ramp;
+	bool buck2_ramp;
+	bool buck3_ramp;
+	bool buck4_ramp;
+};
+
+static const struct sec_voltage_desc buck_voltage_val1 = {
+	.max = 2000000,
+	.min =  600000,
+	.step =   6250,
+};
+
+static const struct sec_voltage_desc buck_voltage_val2 = {
+	.max = 3550000,
+	.min =  750000,
+	.step =  12500,
+};
+
+static const struct sec_voltage_desc buck_voltage_val3 = {
+	.max = 3775000,
+	.min = 3000000,
+	.step =  25000,
+};
+
+static const struct sec_voltage_desc ldo_voltage_val1 = {
+	.max = 3950000,
+	.min =  800000,
+	.step =  50000,
+};
+
+static const struct sec_voltage_desc ldo_voltage_val2 = {
+	.max = 2375000,
+	.min =  800000,
+	.step =  25000,
+};
+
+static const struct sec_voltage_desc *reg_voltage_map[] = {
+	[S2MPS11_LDO1] = &ldo_voltage_val2,
+	[S2MPS11_LDO2] = &ldo_voltage_val1,
+	[S2MPS11_LDO3] = &ldo_voltage_val1,
+	[S2MPS11_LDO4] = &ldo_voltage_val1,
+	[S2MPS11_LDO5] = &ldo_voltage_val1,
+	[S2MPS11_LDO6] = &ldo_voltage_val2,
+	[S2MPS11_LDO7] = &ldo_voltage_val1,
+	[S2MPS11_LDO8] = &ldo_voltage_val1,
+	[S2MPS11_LDO9] = &ldo_voltage_val1,
+	[S2MPS11_LDO10] = &ldo_voltage_val1,
+	[S2MPS11_LDO11] = &ldo_voltage_val2,
+	[S2MPS11_LDO12] = &ldo_voltage_val1,
+	[S2MPS11_LDO13] = &ldo_voltage_val1,
+	[S2MPS11_LDO14] = &ldo_voltage_val1,
+	[S2MPS11_LDO15] = &ldo_voltage_val1,
+	[S2MPS11_LDO16] = &ldo_voltage_val1,
+	[S2MPS11_LDO17] = &ldo_voltage_val1,
+	[S2MPS11_LDO18] = &ldo_voltage_val1,
+	[S2MPS11_LDO19] = &ldo_voltage_val1,
+	[S2MPS11_LDO20] = &ldo_voltage_val1,
+	[S2MPS11_LDO21] = &ldo_voltage_val1,
+	[S2MPS11_LDO22] = &ldo_voltage_val2,
+	[S2MPS11_LDO23] = &ldo_voltage_val2,
+	[S2MPS11_LDO24] = &ldo_voltage_val1,
+	[S2MPS11_LDO25] = &ldo_voltage_val1,
+	[S2MPS11_LDO26] = &ldo_voltage_val1,
+	[S2MPS11_LDO27] = &ldo_voltage_val2,
+	[S2MPS11_LDO28] = &ldo_voltage_val1,
+	[S2MPS11_LDO29] = &ldo_voltage_val1,
+	[S2MPS11_LDO30] = &ldo_voltage_val1,
+	[S2MPS11_LDO31] = &ldo_voltage_val1,
+	[S2MPS11_LDO32] = &ldo_voltage_val1,
+	[S2MPS11_LDO33] = &ldo_voltage_val1,
+	[S2MPS11_LDO34] = &ldo_voltage_val1,
+	[S2MPS11_LDO35] = &ldo_voltage_val1,
+	[S2MPS11_LDO36] = &ldo_voltage_val1,
+	[S2MPS11_LDO37] = &ldo_voltage_val1,
+	[S2MPS11_LDO38] = &ldo_voltage_val1,
+	[S2MPS11_BUCK1] = &buck_voltage_val1,
+	[S2MPS11_BUCK2] = &buck_voltage_val1,
+	[S2MPS11_BUCK3] = &buck_voltage_val1,
+	[S2MPS11_BUCK4] = &buck_voltage_val1,
+	[S2MPS11_BUCK5] = &buck_voltage_val1,
+	[S2MPS11_BUCK6] = &buck_voltage_val1,
+	[S2MPS11_BUCK7] = NULL,
+	[S2MPS11_BUCK8] = NULL,
+	[S2MPS11_BUCK9] = &buck_voltage_val3,
+	[S2MPS11_BUCK10] = &buck_voltage_val2,
+};
+
+static int s2mps11_list_voltage(struct regulator_dev *rdev,
+				unsigned int selector)
+{
+	const struct sec_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+	int val;
+
+	if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
+		return -EINVAL;
+
+	desc = reg_voltage_map[reg_id];
+	if (desc == NULL)
+		return -EINVAL;
+
+	val = desc->min + desc->step * selector;
+	if (val > desc->max)
+		return -EINVAL;
+
+	return val;
+}
+
+unsigned int s2mps11_opmode_reg[][3] = {
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x0, 0x0, 0x0},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x0, 0x0, 0x0},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x0, 0x0, 0x0},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x0, 0x0, 0x0},
+	{0x0, 0x0, 0x0, 0x0},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x2, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x3, 0x1, 0x1},
+	{0x0, 0x1, 0x0, 0x0},
+	{0x0, 0x1, 0x0, 0x0},
+	{0x0, 0x1, 0x0, 0x0},
+};
+
+static int s2mps11_get_register(struct regulator_dev *rdev,
+	int *reg, int *pmic_en)
+{
+	int reg_id = rdev_get_id(rdev);
+	unsigned int mode;
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+
+	switch (reg_id) {
+	case S2MPS11_LDO1 ... S2MPS11_LDO38:
+		*reg = S2MPS11_REG_L1CTRL + (reg_id - S2MPS11_LDO1);
+		break;
+	case S2MPS11_BUCK1 ... S2MPS11_BUCK4:
+		*reg = S2MPS11_REG_B10CTRL1 + (reg_id - S2MPS11_BUCK1) * 2;
+		break;
+	case S2MPS11_BUCK5:
+		*reg = S2MPS11_REG_B5CTRL1;
+		break;
+	case S2MPS11_BUCK6 ... S2MPS11_BUCK8:
+		*reg = S2MPS11_REG_B6CTRL1 + (reg_id - S2MPS11_BUCK6) * 2;
+		break;
+	case S2MPS11_BUCK9 ... S2MPS11_BUCK10:
+		*reg = S2MPS11_REG_B9CTRL1 + (reg_id - S2MPS11_BUCK9) * 2;
+		break;
+	case S2MPS11_AP_EN32KHZ ... S2MPS11_BT_EN32KHZ:
+		*reg = S2MPS11_REG_CTRL1;
+		*pmic_en = 0x01 << (reg_id - S2MPS11_AP_EN32KHZ);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	mode = s2mps11->opmode[reg_id].mode;
+	*pmic_en = s2mps11_opmode_reg[reg_id][mode] << S2MPS11_PMIC_EN_SHIFT;
+
+	return 0;
+}
+
+static int s2mps11_reg_is_enabled(struct regulator_dev *rdev)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int reg_id = rdev_get_id(rdev);
+	int ret, reg;
+	int mask = 0xc0, pmic_en;
+	u8 val;
+
+	ret = s2mps11_get_register(rdev, &reg, &pmic_en);
+	if (ret == -EINVAL)
+		return 1;
+	else if (ret)
+		return ret;
+
+	ret = sec_reg_read(s2mps11->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	switch (reg_id) {
+	case S2MPS11_LDO1 ... S2MPS11_BUCK10:
+		mask = 0xc0;
+		break;
+	case S2MPS11_AP_EN32KHZ:
+		mask = 0x01;
+		break;
+	case S2MPS11_CP_EN32KHZ:
+		mask = 0x02;
+		break;
+	case S2MPS11_BT_EN32KHZ:
+		mask = 0x04;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return (val & mask) == pmic_en;
+}
+
+static int s2mps11_reg_enable(struct regulator_dev *rdev)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int reg_id = rdev_get_id(rdev);
+	int ret, reg;
+	int mask, pmic_en;
+
+	ret = s2mps11_get_register(rdev, &reg, &pmic_en);
+	if (ret)
+		return ret;
+
+	switch (reg_id) {
+	case S2MPS11_LDO1 ... S2MPS11_BUCK10:
+		mask = 0xc0;
+		break;
+	case S2MPS11_AP_EN32KHZ:
+		mask = 0x01;
+		break;
+	case S2MPS11_CP_EN32KHZ:
+		mask = 0x02;
+		break;
+	case S2MPS11_BT_EN32KHZ:
+		mask = 0x04;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sec_reg_update(s2mps11->iodev, reg, pmic_en, mask);
+}
+
+static int s2mps11_reg_disable(struct regulator_dev *rdev)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int reg_id = rdev_get_id(rdev);
+	int ret, reg;
+	int  mask, pmic_en;
+
+	ret = s2mps11_get_register(rdev, &reg, &pmic_en);
+	if (ret)
+		return ret;
+
+	switch (reg_id) {
+	case S2MPS11_LDO1 ... S2MPS11_BUCK10:
+		mask = 0xc0;
+		break;
+	case S2MPS11_AP_EN32KHZ:
+		mask = 0x01;
+		break;
+	case S2MPS11_CP_EN32KHZ:
+		mask = 0x02;
+		break;
+	case S2MPS11_BT_EN32KHZ:
+		mask = 0x04;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sec_reg_update(s2mps11->iodev, reg, ~mask, mask);
+}
+
+static int s2mps11_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+{
+	int reg_id = rdev_get_id(rdev);
+	int reg;
+
+	switch (reg_id) {
+	case S2MPS11_LDO1 ... S2MPS11_LDO38:
+		reg = S2MPS11_REG_L1CTRL + (reg_id - S2MPS11_LDO1);
+		break;
+	case S2MPS11_BUCK1 ... S2MPS11_BUCK4:
+		reg = S2MPS11_REG_B1CTRL2 + (reg_id - S2MPS11_BUCK1) * 2;
+		break;
+	case S2MPS11_BUCK5:
+		reg = S2MPS11_REG_B5CTRL2;
+		break;
+	case S2MPS11_BUCK6 ... S2MPS11_BUCK8:
+		reg = S2MPS11_REG_B6CTRL2 + (reg_id - S2MPS11_BUCK6) * 2;
+		break;
+	case S2MPS11_BUCK9 ... S2MPS11_BUCK10:
+		reg = S2MPS11_REG_B9CTRL2 + (reg_id - S2MPS11_BUCK9) * 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_reg = reg;
+
+	return 0;
+}
+
+static int s2mps11_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int reg, mask = 0xff, ret;
+	int reg_id = rdev_get_id(rdev);
+	u8 val;
+
+	ret = s2mps11_get_voltage_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	switch (reg_id) {
+	case S2MPS11_BUCK1 ... S2MPS11_BUCK8:
+	case S2MPS11_BUCK10:
+		break;
+	case S2MPS11_LDO1 ... S2MPS11_LDO38:
+		mask = 0x3f;
+		break;
+	case S2MPS11_BUCK9:
+		mask = 0x1f;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = sec_reg_read(s2mps11->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	val &= mask;
+
+	return val;
+}
+
+static inline int s2mps11_convert_voltage_to_sel(
+		const struct sec_voltage_desc *desc,
+		int min_vol, int max_vol)
+{
+	int selector = 0;
+
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	selector = (min_vol - desc->min) / desc->step;
+
+	if (desc->min + desc->step * selector > max_vol)
+		return -EINVAL;
+
+	return selector;
+}
+
+static int s2mps11_set_voltage(struct regulator_dev *rdev,
+				int min_uV, int max_uV, unsigned *selector)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int min_vol = min_uV, max_vol = max_uV;
+	const struct sec_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+	int sel, reg, ret, mask;
+	u8 val;
+
+	mask = (reg_id < S2MPS11_BUCK1) ? 0x3f : 0xff;
+
+	desc = reg_voltage_map[reg_id];
+
+	sel = s2mps11_convert_voltage_to_sel(desc, min_vol, max_vol);
+	if (sel < 0)
+		return sel;
+
+	ret = s2mps11_get_voltage_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	sec_reg_read(s2mps11->iodev, reg, &val);
+	val &= ~mask;
+	val |= sel;
+
+	ret = sec_reg_write(s2mps11->iodev, reg, val);
+	*selector = sel;
+
+	return ret;
+}
+
+static int s2mps11_set_voltage_time_sel(struct regulator_dev *rdev,
+					     unsigned int old_sel,
+					     unsigned int new_sel)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	const struct sec_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+	int ramp_delay = 0;
+
+	switch (reg_id) {
+	case S2MPS11_BUCK1:
+	case S2MPS11_BUCK6:
+		ramp_delay = s2mps11->ramp_delay16;
+		break;
+	case S2MPS11_BUCK2:
+		ramp_delay = s2mps11->ramp_delay2;
+		break;
+	case S2MPS11_BUCK3 ... S2MPS11_BUCK4:
+		ramp_delay = s2mps11->ramp_delay34;
+		break;
+	case S2MPS11_BUCK5:
+		ramp_delay = s2mps11->ramp_delay5;
+		break;
+	case S2MPS11_BUCK7 ... S2MPS11_BUCK8:
+	case S2MPS11_BUCK10:
+		ramp_delay = s2mps11->ramp_delay7810;
+		break;
+	case S2MPS11_BUCK9:
+		ramp_delay = s2mps11->ramp_delay9;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	desc = reg_voltage_map[reg_id];
+
+	if (((old_sel < new_sel) && (reg_id > S2MPS11_LDO38)) && ramp_delay) {
+		return DIV_ROUND_UP(desc->step * (new_sel - old_sel),
+			ramp_delay * 1000);
+	}
+
+	return 0;
+}
+
+static int s2mps11_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	int reg, mask = 0xff, ret;
+	int reg_id = rdev_get_id(rdev);
+
+	ret = s2mps11_get_voltage_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	switch (reg_id) {
+	case S2MPS11_BUCK1 ... S2MPS11_BUCK8:
+	case S2MPS11_BUCK10:
+		break;
+	case S2MPS11_LDO1 ... S2MPS11_LDO38:
+		mask = 0x3f;
+		break;
+	case S2MPS11_BUCK9:
+		mask = 0x1f;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return sec_reg_update(s2mps11->iodev, reg, selector, mask);
+}
+
+static int get_ramp_delay(int ramp_delay)
+{
+	unsigned char cnt = 0;
+
+	ramp_delay /= 6;
+
+	while (true) {
+		ramp_delay = ramp_delay >> 1;
+		if (ramp_delay == 0)
+			break;
+		cnt++;
+	}
+	return cnt;
+}
+
+static struct regulator_ops s2mps11_ldo_ops = {
+	.list_voltage		= s2mps11_list_voltage,
+	.is_enabled		= s2mps11_reg_is_enabled,
+	.enable			= s2mps11_reg_enable,
+	.disable		= s2mps11_reg_disable,
+	.get_voltage_sel	= s2mps11_get_voltage_sel,
+	.set_voltage		= s2mps11_set_voltage,
+	.set_voltage_time_sel	= s2mps11_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mps11_buck_ops = {
+	.list_voltage		= s2mps11_list_voltage,
+	.is_enabled		= s2mps11_reg_is_enabled,
+	.enable			= s2mps11_reg_enable,
+	.disable		= s2mps11_reg_disable,
+	.get_voltage_sel	= s2mps11_get_voltage_sel,
+	.set_voltage_sel	= s2mps11_set_voltage_sel,
+	.set_voltage_time_sel	= s2mps11_set_voltage_time_sel,
+};
+
+#define regulator_desc_ldo(num)		{	\
+	.name		= "LDO"#num,		\
+	.id		= S2MPS11_LDO##num,	\
+	.ops		= &s2mps11_ldo_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+#define regulator_desc_buck(num)	{	\
+	.name		= "BUCK"#num,		\
+	.id		= S2MPS11_BUCK##num,	\
+	.ops		= &s2mps11_buck_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_desc_ldo(1),
+	regulator_desc_ldo(2),
+	regulator_desc_ldo(3),
+	regulator_desc_ldo(4),
+	regulator_desc_ldo(5),
+	regulator_desc_ldo(6),
+	regulator_desc_ldo(7),
+	regulator_desc_ldo(8),
+	regulator_desc_ldo(9),
+	regulator_desc_ldo(10),
+	regulator_desc_ldo(11),
+	regulator_desc_ldo(12),
+	regulator_desc_ldo(13),
+	regulator_desc_ldo(14),
+	regulator_desc_ldo(15),
+	regulator_desc_ldo(16),
+	regulator_desc_ldo(17),
+	regulator_desc_ldo(18),
+	regulator_desc_ldo(19),
+	regulator_desc_ldo(20),
+	regulator_desc_ldo(21),
+	regulator_desc_ldo(22),
+	regulator_desc_ldo(23),
+	regulator_desc_ldo(24),
+	regulator_desc_ldo(25),
+	regulator_desc_ldo(26),
+	regulator_desc_ldo(27),
+	regulator_desc_ldo(28),
+	regulator_desc_ldo(29),
+	regulator_desc_ldo(30),
+	regulator_desc_ldo(31),
+	regulator_desc_ldo(32),
+	regulator_desc_ldo(33),
+	regulator_desc_ldo(34),
+	regulator_desc_ldo(35),
+	regulator_desc_ldo(36),
+	regulator_desc_ldo(37),
+	regulator_desc_ldo(38),
+	regulator_desc_buck(1),
+	regulator_desc_buck(2),
+	regulator_desc_buck(3),
+	regulator_desc_buck(4),
+	regulator_desc_buck(5),
+	regulator_desc_buck(6),
+	regulator_desc_buck(7),
+	regulator_desc_buck(8),
+	regulator_desc_buck(9),
+	regulator_desc_buck(10),
+};
+
+static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
+{
+	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct sec_pmic_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_config config = { };
+	struct regulator_dev **rdev;
+	struct s2mps11_info *s2mps11;
+	int i, ret, size;
+	unsigned char ramp_enable, ramp_reg = 0;
+
+	if (!pdata) {
+		dev_err(pdev->dev.parent, "Platform data not supplied\n");
+		return -ENODEV;
+	}
+
+	s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
+				GFP_KERNEL);
+	if (!s2mps11)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * pdata->num_regulators;
+	s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (!s2mps11->rdev) {
+		return -ENOMEM;
+	}
+
+	rdev = s2mps11->rdev;
+	s2mps11->dev = &pdev->dev;
+	s2mps11->iodev = iodev;
+	s2mps11->num_regulators = pdata->num_regulators;
+	platform_set_drvdata(pdev, s2mps11);
+
+	s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
+	s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
+	s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
+	s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
+	s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
+	s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
+
+	s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
+	s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
+	s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
+	s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
+	s2mps11->opmode = pdata->opmode;
+
+	ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
+		(s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
+
+	if (ramp_enable) {
+		if (s2mps11->buck2_ramp)
+			ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6;
+		if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
+			ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4;
+		sec_reg_update(s2mps11->iodev, S2MPS11_REG_RAMP,
+			ramp_reg | ramp_enable, 0xff);
+	}
+
+	ramp_reg &= 0x00;
+	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6;
+	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4;
+	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2;
+	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
+	sec_reg_update(s2mps11->iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg, 0xff);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		const struct sec_voltage_desc *desc;
+		int id = pdata->regulators[i].id;
+
+		desc = reg_voltage_map[id];
+		if (desc)
+			regulators[id].n_voltages =
+				(desc->max - desc->min) / desc->step + 1;
+
+		config.dev = s2mps11->dev;
+		config.init_data = pdata->regulators[i].initdata;
+		config.driver_data = s2mps11;
+
+		rdev[i] = regulator_register(&regulators[id], &config);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(s2mps11->dev, "regulator init failed for %d\n",
+					id);
+			rdev[i] = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	for (i = 0; i < s2mps11->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	return ret;
+}
+
+static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
+{
+	struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = s2mps11->rdev;
+	int i;
+
+	for (i = 0; i < s2mps11->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	return 0;
+}
+
+static const struct platform_device_id s2mps11_pmic_id[] = {
+	{ "s2mps11-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
+
+static struct platform_driver s2mps11_pmic_driver = {
+	.driver = {
+		.name = "s2mps11-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = s2mps11_pmic_probe,
+	.remove = __devexit_p(s2mps11_pmic_remove),
+	.id_table = s2mps11_pmic_id,
+};
+
+static int __init s2mps11_pmic_init(void)
+{
+	return platform_driver_register(&s2mps11_pmic_driver);
+}
+subsys_initcall(s2mps11_pmic_init);
+
+static void __exit s2mps11_pmic_exit(void)
+{
+	platform_driver_unregister(&s2mps11_pmic_driver);
+}
+module_exit(s2mps11_pmic_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@...sung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index b98cad1..5c40b2e 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -45,12 +45,6 @@ struct s5m8767_info {
 	int buck_gpioindex;
 };
 
-struct sec_voltage_desc {
-	int max;
-	int min;
-	int step;
-};
-
 static const struct sec_voltage_desc buck_voltage_val1 = {
 	.max = 2225000,
 	.min =  650000,
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index be6277a..d888f66 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -20,6 +20,7 @@ enum sec_device_type {
 	S5M8751X,
 	S5M8763X,
 	S5M8767X,
+	S2MPS11X,
 };
 
 /**
@@ -98,9 +99,17 @@ struct sec_pmic_platform_data {
 	int				buck4_default_idx;
 
 	int                             buck_ramp_delay;
+
+	int				buck2_ramp_delay;
+	int				buck34_ramp_delay;
+	int				buck5_ramp_delay;
+	int				buck16_ramp_delay;
+	int				buck7810_ramp_delay;
+	int				buck9_ramp_delay;
 	bool                            buck2_ramp_enable;
 	bool                            buck3_ramp_enable;
 	bool                            buck4_ramp_enable;
+	bool				buck6_ramp_enable;
 
 	int				buck2_init;
 	int				buck3_init;
@@ -144,4 +153,10 @@ enum sec_opmode {
 	SEC_OPMODE_SUSPEND,
 };
 
+struct sec_voltage_desc {
+	int max;
+	int min;
+	int step;
+};
+
 #endif /*  __LINUX_MFD_SEC_CORE_H */
diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h
new file mode 100644
index 0000000..44027e9
--- /dev/null
+++ b/include/linux/mfd/samsung/s2mps11.h
@@ -0,0 +1,179 @@
+/*
+ * s2mps11.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  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.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPS11_H
+#define __LINUX_MFD_S2MPS11_H
+
+/* S2MPS11 registers */
+enum s2mps11_reg {
+	S2MPS11_REG_ID,
+	S2MPS11_REG_INT1,
+	S2MPS11_REG_INT2,
+	S2MPS11_REG_INT3,
+	S2MPS11_REG_INT1M,
+	S2MPS11_REG_INT2M,
+	S2MPS11_REG_INT3M,
+	S2MPS11_REG_ST1,
+	S2MPS11_REG_ST2,
+	S2MPS11_REG_OFFSRC,
+	S2MPS11_REG_PWRONSRC,
+	S2MPS11_REG_RTC_CTRL,
+	S2MPS11_REG_CTRL1,
+	S2MPS11_REG_ETC_TEST,
+	S2MPS11_REG_RSVD3,
+	S2MPS11_REG_BU_CHG,
+	S2MPS11_REG_RAMP,
+	S2MPS11_REG_RAMP_BUCK,
+	S2MPS11_REG_LDO1_8,
+	S2MPS11_REG_LDO9_16,
+	S2MPS11_REG_LDO17_24,
+	S2MPS11_REG_LDO25_32,
+	S2MPS11_REG_LDO33_38,
+	S2MPS11_REG_LDO1_8_1,
+	S2MPS11_REG_LDO9_16_1,
+	S2MPS11_REG_LDO17_24_1,
+	S2MPS11_REG_LDO25_32_1,
+	S2MPS11_REG_LDO33_38_1,
+	S2MPS11_REG_OTP_ADRL,
+	S2MPS11_REG_OTP_ADRH,
+	S2MPS11_REG_OTP_DATA,
+	S2MPS11_REG_MON1SEL,
+	S2MPS11_REG_MON2SEL,
+	S2MPS11_REG_LEE,
+	S2MPS11_REG_RSVD_NO,
+	S2MPS11_REG_UVLO,
+	S2MPS11_REG_LEE_NO,
+	S2MPS11_REG_B1CTRL1,
+	S2MPS11_REG_B1CTRL2,
+	S2MPS11_REG_B2CTRL1,
+	S2MPS11_REG_B2CTRL2,
+	S2MPS11_REG_B3CTRL1,
+	S2MPS11_REG_B3CTRL2,
+	S2MPS11_REG_B4CTRL1,
+	S2MPS11_REG_B4CTRL2,
+	S2MPS11_REG_B5CTRL1,
+	S2MPS11_REG_BUCK5_SW,
+	S2MPS11_REG_B5CTRL2,
+	S2MPS11_REG_B5CTRL3,
+	S2MPS11_REG_B5CTRL4,
+	S2MPS11_REG_B5CTRL5,
+	S2MPS11_REG_B6CTRL1,
+	S2MPS11_REG_B6CTRL2,
+	S2MPS11_REG_B7CTRL1,
+	S2MPS11_REG_B7CTRL2,
+	S2MPS11_REG_B8CTRL1,
+	S2MPS11_REG_B8CTRL2,
+	S2MPS11_REG_B9CTRL1,
+	S2MPS11_REG_B9CTRL2,
+	S2MPS11_REG_B10CTRL1,
+	S2MPS11_REG_B10CTRL2,
+	S2MPS11_REG_L1CTRL,
+	S2MPS11_REG_L2CTRL,
+	S2MPS11_REG_L3CTRL,
+	S2MPS11_REG_L4CTRL,
+	S2MPS11_REG_L5CTRL,
+	S2MPS11_REG_L6CTRL,
+	S2MPS11_REG_L7CTRL,
+	S2MPS11_REG_L8CTRL,
+	S2MPS11_REG_L9CTRL,
+	S2MPS11_REG_L10CTRL,
+	S2MPS11_REG_L11CTRL,
+	S2MPS11_REG_L12CTRL,
+	S2MPS11_REG_L13CTRL,
+	S2MPS11_REG_L14CTRL,
+	S2MPS11_REG_L15CTRL,
+	S2MPS11_REG_L16CTRL,
+	S2MPS11_REG_L17CTRL,
+	S2MPS11_REG_L18CTRL,
+	S2MPS11_REG_L19CTRL,
+	S2MPS11_REG_L20CTRL,
+	S2MPS11_REG_L21CTRL,
+	S2MPS11_REG_L22CTRL,
+	S2MPS11_REG_L23CTRL,
+	S2MPS11_REG_L24CTRL,
+	S2MPS11_REG_L25CTRL,
+	S2MPS11_REG_L26CTRL,
+	S2MPS11_REG_L27CTRL,
+	S2MPS11_REG_L28CTRL,
+	S2MPS11_REG_L29CTRL,
+	S2MPS11_REG_L30CTRL,
+	S2MPS11_REG_L31CTRL,
+	S2MPS11_REG_L32CTRL,
+	S2MPS11_REG_L33CTRL,
+	S2MPS11_REG_L34CTRL,
+	S2MPS11_REG_L35CTRL,
+	S2MPS11_REG_L36CTRL,
+	S2MPS11_REG_L37CTRL,
+	S2MPS11_REG_L38CTRL,
+};
+
+/* S2MPS11 regulator ids */
+enum s2mps11_regulators {
+	S2MPS11_LDO1,
+	S2MPS11_LDO2,
+	S2MPS11_LDO3,
+	S2MPS11_LDO4,
+	S2MPS11_LDO5,
+	S2MPS11_LDO6,
+	S2MPS11_LDO7,
+	S2MPS11_LDO8,
+	S2MPS11_LDO9,
+	S2MPS11_LDO10,
+	S2MPS11_LDO11,
+	S2MPS11_LDO12,
+	S2MPS11_LDO13,
+	S2MPS11_LDO14,
+	S2MPS11_LDO15,
+	S2MPS11_LDO16,
+	S2MPS11_LDO17,
+	S2MPS11_LDO18,
+	S2MPS11_LDO19,
+	S2MPS11_LDO20,
+	S2MPS11_LDO21,
+	S2MPS11_LDO22,
+	S2MPS11_LDO23,
+	S2MPS11_LDO24,
+	S2MPS11_LDO25,
+	S2MPS11_LDO26,
+	S2MPS11_LDO27,
+	S2MPS11_LDO28,
+	S2MPS11_LDO29,
+	S2MPS11_LDO30,
+	S2MPS11_LDO31,
+	S2MPS11_LDO32,
+	S2MPS11_LDO33,
+	S2MPS11_LDO34,
+	S2MPS11_LDO35,
+	S2MPS11_LDO36,
+	S2MPS11_LDO37,
+	S2MPS11_LDO38,
+	S2MPS11_BUCK1,
+	S2MPS11_BUCK2,
+	S2MPS11_BUCK3,
+	S2MPS11_BUCK4,
+	S2MPS11_BUCK5,
+	S2MPS11_BUCK6,
+	S2MPS11_BUCK7,
+	S2MPS11_BUCK8,
+	S2MPS11_BUCK9,
+	S2MPS11_BUCK10,
+	S2MPS11_AP_EN32KHZ,
+	S2MPS11_CP_EN32KHZ,
+	S2MPS11_BT_EN32KHZ,
+
+	S2MPS11_REG_MAX,
+};
+
+#define S2MPS11_PMIC_EN_SHIFT	6
+
+#endif /*  __LINUX_MFD_S2MPS11_H */
-- 
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ