diff options
Diffstat (limited to 'drivers/regulator/lp8788-ldo.c')
| -rw-r--r-- | drivers/regulator/lp8788-ldo.c | 842 | 
1 files changed, 842 insertions, 0 deletions
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c new file mode 100644 index 00000000000..d2122e41a96 --- /dev/null +++ b/drivers/regulator/lp8788-ldo.c @@ -0,0 +1,842 @@ +/* + * TI LP8788 MFD - ldo regulator driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * 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/module.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/gpio.h> +#include <linux/mfd/lp8788.h> + +/* register address */ +#define LP8788_EN_LDO_A			0x0D	/* DLDO 1 ~ 8 */ +#define LP8788_EN_LDO_B			0x0E	/* DLDO 9 ~ 12, ALDO 1 ~ 4 */ +#define LP8788_EN_LDO_C			0x0F	/* ALDO 5 ~ 10 */ +#define LP8788_EN_SEL			0x10 +#define LP8788_DLDO1_VOUT		0x2E +#define LP8788_DLDO2_VOUT		0x2F +#define LP8788_DLDO3_VOUT		0x30 +#define LP8788_DLDO4_VOUT		0x31 +#define LP8788_DLDO5_VOUT		0x32 +#define LP8788_DLDO6_VOUT		0x33 +#define LP8788_DLDO7_VOUT		0x34 +#define LP8788_DLDO8_VOUT		0x35 +#define LP8788_DLDO9_VOUT		0x36 +#define LP8788_DLDO10_VOUT		0x37 +#define LP8788_DLDO11_VOUT		0x38 +#define LP8788_DLDO12_VOUT		0x39 +#define LP8788_ALDO1_VOUT		0x3A +#define LP8788_ALDO2_VOUT		0x3B +#define LP8788_ALDO3_VOUT		0x3C +#define LP8788_ALDO4_VOUT		0x3D +#define LP8788_ALDO5_VOUT		0x3E +#define LP8788_ALDO6_VOUT		0x3F +#define LP8788_ALDO7_VOUT		0x40 +#define LP8788_ALDO8_VOUT		0x41 +#define LP8788_ALDO9_VOUT		0x42 +#define LP8788_ALDO10_VOUT		0x43 +#define LP8788_DLDO1_TIMESTEP		0x44 + +/* mask/shift bits */ +#define LP8788_EN_DLDO1_M		BIT(0)	/* Addr 0Dh ~ 0Fh */ +#define LP8788_EN_DLDO2_M		BIT(1) +#define LP8788_EN_DLDO3_M		BIT(2) +#define LP8788_EN_DLDO4_M		BIT(3) +#define LP8788_EN_DLDO5_M		BIT(4) +#define LP8788_EN_DLDO6_M		BIT(5) +#define LP8788_EN_DLDO7_M		BIT(6) +#define LP8788_EN_DLDO8_M		BIT(7) +#define LP8788_EN_DLDO9_M		BIT(0) +#define LP8788_EN_DLDO10_M		BIT(1) +#define LP8788_EN_DLDO11_M		BIT(2) +#define LP8788_EN_DLDO12_M		BIT(3) +#define LP8788_EN_ALDO1_M		BIT(4) +#define LP8788_EN_ALDO2_M		BIT(5) +#define LP8788_EN_ALDO3_M		BIT(6) +#define LP8788_EN_ALDO4_M		BIT(7) +#define LP8788_EN_ALDO5_M		BIT(0) +#define LP8788_EN_ALDO6_M		BIT(1) +#define LP8788_EN_ALDO7_M		BIT(2) +#define LP8788_EN_ALDO8_M		BIT(3) +#define LP8788_EN_ALDO9_M		BIT(4) +#define LP8788_EN_ALDO10_M		BIT(5) +#define LP8788_EN_SEL_DLDO911_M		BIT(0)	/* Addr 10h */ +#define LP8788_EN_SEL_DLDO7_M		BIT(1) +#define LP8788_EN_SEL_ALDO7_M		BIT(2) +#define LP8788_EN_SEL_ALDO5_M		BIT(3) +#define LP8788_EN_SEL_ALDO234_M		BIT(4) +#define LP8788_EN_SEL_ALDO1_M		BIT(5) +#define LP8788_VOUT_5BIT_M		0x1F	/* Addr 2Eh ~ 43h */ +#define LP8788_VOUT_4BIT_M		0x0F +#define LP8788_VOUT_3BIT_M		0x07 +#define LP8788_VOUT_1BIT_M		0x01 +#define LP8788_STARTUP_TIME_M		0xF8	/* Addr 44h ~ 59h */ +#define LP8788_STARTUP_TIME_S		3 + +#define ENABLE_TIME_USEC		32 +#define ENABLE				GPIOF_OUT_INIT_HIGH +#define DISABLE				GPIOF_OUT_INIT_LOW + +enum lp8788_enable_mode { +	REGISTER, +	EXTPIN, +}; + +enum lp8788_ldo_id { +	DLDO1, +	DLDO2, +	DLDO3, +	DLDO4, +	DLDO5, +	DLDO6, +	DLDO7, +	DLDO8, +	DLDO9, +	DLDO10, +	DLDO11, +	DLDO12, +	ALDO1, +	ALDO2, +	ALDO3, +	ALDO4, +	ALDO5, +	ALDO6, +	ALDO7, +	ALDO8, +	ALDO9, +	ALDO10, +}; + +struct lp8788_ldo { +	struct lp8788 *lp; +	struct regulator_desc *desc; +	struct regulator_dev *regulator; +	struct lp8788_ldo_enable_pin *en_pin; +}; + +/* DLDO 1, 2, 3, 9 voltage table */ +const int lp8788_dldo1239_vtbl[] = { +	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, +	2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000, +	2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, +	2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, +}; + +/* DLDO 4 voltage table */ +static const int lp8788_dldo4_vtbl[] = { 1800000, 3000000 }; + +/* DLDO 5, 7, 8 and ALDO 6 voltage table */ +static const int lp8788_dldo578_aldo6_vtbl[] = { +	1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, +	2600000, 2700000, 2800000, 2900000, 3000000, 3000000, 3000000, 3000000, +}; + +/* DLDO 6 voltage table */ +static const int lp8788_dldo6_vtbl[] = { +	3000000, 3100000, 3200000, 3300000, 3400000, 3500000, 3600000, 3600000, +}; + +/* DLDO 10, 11 voltage table */ +static const int lp8788_dldo1011_vtbl[] = { +	1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, +	1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, +}; + +/* ALDO 1 voltage table */ +static const int lp8788_aldo1_vtbl[] = { 1800000, 2850000 }; + +/* ALDO 7 voltage table */ +static const int lp8788_aldo7_vtbl[] = { +	1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000, +}; + +static enum lp8788_ldo_id lp8788_dldo_id[] = { +	DLDO1, +	DLDO2, +	DLDO3, +	DLDO4, +	DLDO5, +	DLDO6, +	DLDO7, +	DLDO8, +	DLDO9, +	DLDO10, +	DLDO11, +	DLDO12, +}; + +static enum lp8788_ldo_id lp8788_aldo_id[] = { +	ALDO1, +	ALDO2, +	ALDO3, +	ALDO4, +	ALDO5, +	ALDO6, +	ALDO7, +	ALDO8, +	ALDO9, +	ALDO10, +}; + +/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7 +   : can be enabled either by external pin or by i2c register */ +static enum lp8788_enable_mode +lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id) +{ +	int ret; +	u8 val, mask; + +	ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val); +	if (ret) +		return ret; + +	switch (id) { +	case DLDO7: +		mask =  LP8788_EN_SEL_DLDO7_M; +		break; +	case DLDO9: +	case DLDO11: +		mask =  LP8788_EN_SEL_DLDO911_M; +		break; +	case ALDO1: +		mask =  LP8788_EN_SEL_ALDO1_M; +		break; +	case ALDO2 ... ALDO4: +		mask =  LP8788_EN_SEL_ALDO234_M; +		break; +	case ALDO5: +		mask =  LP8788_EN_SEL_ALDO5_M; +		break; +	case ALDO7: +		mask =  LP8788_EN_SEL_ALDO7_M; +		break; +	default: +		return REGISTER; +	} + +	return val & mask ? EXTPIN : REGISTER; +} + +static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate) +{ +	struct lp8788_ldo_enable_pin *pin = ldo->en_pin; + +	if (!pin) +		return -EINVAL; + +	if (gpio_is_valid(pin->gpio)) +		gpio_set_value(pin->gpio, pinstate); + +	return 0; +} + +static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo) +{ +	struct lp8788_ldo_enable_pin *pin = ldo->en_pin; + +	if (!pin) +		return -EINVAL; + +	return gpio_get_value(pin->gpio) ? 1 : 0; +} + +static int lp8788_ldo_enable(struct regulator_dev *rdev) +{ +	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); +	enum lp8788_ldo_id id = rdev_get_id(rdev); +	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + +	switch (mode) { +	case EXTPIN: +		return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE); +	case REGISTER: +		return regulator_enable_regmap(rdev); +	default: +		return -EINVAL; +	} +} + +static int lp8788_ldo_disable(struct regulator_dev *rdev) +{ +	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); +	enum lp8788_ldo_id id = rdev_get_id(rdev); +	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + +	switch (mode) { +	case EXTPIN: +		return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE); +	case REGISTER: +		return regulator_disable_regmap(rdev); +	default: +		return -EINVAL; +	} +} + +static int lp8788_ldo_is_enabled(struct regulator_dev *rdev) +{ +	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); +	enum lp8788_ldo_id id = rdev_get_id(rdev); +	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); + +	switch (mode) { +	case EXTPIN: +		return lp8788_ldo_is_enabled_by_extern_pin(ldo); +	case REGISTER: +		return regulator_is_enabled_regmap(rdev); +	default: +		return -EINVAL; +	} +} + +static int lp8788_ldo_enable_time(struct regulator_dev *rdev) +{ +	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); +	enum lp8788_ldo_id id = rdev_get_id(rdev); +	u8 val, addr = LP8788_DLDO1_TIMESTEP + id; + +	if (lp8788_read_byte(ldo->lp, addr, &val)) +		return -EINVAL; + +	val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S; + +	return ENABLE_TIME_USEC * val; +} + +static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev) +{ +	enum lp8788_ldo_id id = rdev_get_id(rdev); + +	switch (id) { +	case ALDO2 ... ALDO5: +		return 2850000; +	case DLDO12: +	case ALDO8 ... ALDO9: +		return 2500000; +	case ALDO10: +		return 1100000; +	default: +		return -EINVAL; +	} +} + +static struct regulator_ops lp8788_ldo_voltage_table_ops = { +	.list_voltage = regulator_list_voltage_table, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.enable = lp8788_ldo_enable, +	.disable = lp8788_ldo_disable, +	.is_enabled = lp8788_ldo_is_enabled, +	.enable_time = lp8788_ldo_enable_time, +}; + +static struct regulator_ops lp8788_ldo_voltage_fixed_ops = { +	.get_voltage = lp8788_ldo_fixed_get_voltage, +	.enable = lp8788_ldo_enable, +	.disable = lp8788_ldo_disable, +	.is_enabled = lp8788_ldo_is_enabled, +	.enable_time = lp8788_ldo_enable_time, +}; + +static struct regulator_desc lp8788_dldo_desc[] = { +	{ +		.name = "dldo1", +		.id = DLDO1, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), +		.volt_table = lp8788_dldo1239_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO1_VOUT, +		.vsel_mask = LP8788_VOUT_5BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO1_M, +	}, +	{ +		.name = "dldo2", +		.id = DLDO2, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), +		.volt_table = lp8788_dldo1239_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO2_VOUT, +		.vsel_mask = LP8788_VOUT_5BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO2_M, +	}, +	{ +		.name = "dldo3", +		.id = DLDO3, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), +		.volt_table = lp8788_dldo1239_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO3_VOUT, +		.vsel_mask = LP8788_VOUT_5BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO3_M, +	}, +	{ +		.name = "dldo4", +		.id = DLDO4, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo4_vtbl), +		.volt_table = lp8788_dldo4_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO4_VOUT, +		.vsel_mask = LP8788_VOUT_1BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO4_M, +	}, +	{ +		.name = "dldo5", +		.id = DLDO5, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), +		.volt_table = lp8788_dldo578_aldo6_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO5_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO5_M, +	}, +	{ +		.name = "dldo6", +		.id = DLDO6, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo6_vtbl), +		.volt_table = lp8788_dldo6_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO6_VOUT, +		.vsel_mask = LP8788_VOUT_3BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO6_M, +	}, +	{ +		.name = "dldo7", +		.id = DLDO7, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), +		.volt_table = lp8788_dldo578_aldo6_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO7_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO7_M, +	}, +	{ +		.name = "dldo8", +		.id = DLDO8, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), +		.volt_table = lp8788_dldo578_aldo6_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO8_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_A, +		.enable_mask = LP8788_EN_DLDO8_M, +	}, +	{ +		.name = "dldo9", +		.id = DLDO9, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl), +		.volt_table = lp8788_dldo1239_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO9_VOUT, +		.vsel_mask = LP8788_VOUT_5BIT_M, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_DLDO9_M, +	}, +	{ +		.name = "dldo10", +		.id = DLDO10, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl), +		.volt_table = lp8788_dldo1011_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO10_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_DLDO10_M, +	}, +	{ +		.name = "dldo11", +		.id = DLDO11, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl), +		.volt_table = lp8788_dldo1011_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_DLDO11_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_DLDO11_M, +	}, +	{ +		.name = "dldo12", +		.id = DLDO12, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_DLDO12_M, +	}, +}; + +static struct regulator_desc lp8788_aldo_desc[] = { +	{ +		.name = "aldo1", +		.id = ALDO1, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_aldo1_vtbl), +		.volt_table = lp8788_aldo1_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_ALDO1_VOUT, +		.vsel_mask = LP8788_VOUT_1BIT_M, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_ALDO1_M, +	}, +	{ +		.name = "aldo2", +		.id = ALDO2, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_ALDO2_M, +	}, +	{ +		.name = "aldo3", +		.id = ALDO3, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_ALDO3_M, +	}, +	{ +		.name = "aldo4", +		.id = ALDO4, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_B, +		.enable_mask = LP8788_EN_ALDO4_M, +	}, +	{ +		.name = "aldo5", +		.id = ALDO5, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO5_M, +	}, +	{ +		.name = "aldo6", +		.id = ALDO6, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl), +		.volt_table = lp8788_dldo578_aldo6_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_ALDO6_VOUT, +		.vsel_mask = LP8788_VOUT_4BIT_M, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO6_M, +	}, +	{ +		.name = "aldo7", +		.id = ALDO7, +		.ops = &lp8788_ldo_voltage_table_ops, +		.n_voltages = ARRAY_SIZE(lp8788_aldo7_vtbl), +		.volt_table = lp8788_aldo7_vtbl, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.vsel_reg = LP8788_ALDO7_VOUT, +		.vsel_mask = LP8788_VOUT_3BIT_M, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO7_M, +	}, +	{ +		.name = "aldo8", +		.id = ALDO8, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO8_M, +	}, +	{ +		.name = "aldo9", +		.id = ALDO9, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO9_M, +	}, +	{ +		.name = "aldo10", +		.id = ALDO10, +		.ops = &lp8788_ldo_voltage_fixed_ops, +		.type = REGULATOR_VOLTAGE, +		.owner = THIS_MODULE, +		.enable_reg = LP8788_EN_LDO_C, +		.enable_mask = LP8788_EN_ALDO10_M, +	}, +}; + +static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, +				enum lp8788_ext_ldo_en_id id) +{ +	struct device *dev = ldo->lp->dev; +	struct lp8788_ldo_enable_pin *pin = ldo->en_pin; +	int ret, gpio, pinstate; +	char *name[] = { +		[EN_ALDO1]   = "LP8788_EN_ALDO1", +		[EN_ALDO234] = "LP8788_EN_ALDO234", +		[EN_ALDO5]   = "LP8788_EN_ALDO5", +		[EN_ALDO7]   = "LP8788_EN_ALDO7", +		[EN_DLDO7]   = "LP8788_EN_DLDO7", +		[EN_DLDO911] = "LP8788_EN_DLDO911", +	}; + +	gpio = pin->gpio; +	if (!gpio_is_valid(gpio)) { +		dev_err(dev, "invalid gpio: %d\n", gpio); +		return -EINVAL; +	} + +	pinstate = pin->init_state; +	ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]); +	if (ret == -EBUSY) { +		dev_warn(dev, "gpio%d already used\n", gpio); +		return 0; +	} + +	return ret; +} + +static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, +					enum lp8788_ldo_id id) +{ +	int ret; +	struct lp8788 *lp = ldo->lp; +	struct lp8788_platform_data *pdata = lp->pdata; +	enum lp8788_ext_ldo_en_id enable_id; +	u8 en_mask[] = { +		[EN_ALDO1]   = LP8788_EN_SEL_ALDO1_M, +		[EN_ALDO234] = LP8788_EN_SEL_ALDO234_M, +		[EN_ALDO5]   = LP8788_EN_SEL_ALDO5_M, +		[EN_ALDO7]   = LP8788_EN_SEL_ALDO7_M, +		[EN_DLDO7]   = LP8788_EN_SEL_DLDO7_M, +		[EN_DLDO911] = LP8788_EN_SEL_DLDO911_M, +	}; +	u8 val[] = { +		[EN_ALDO1]   = 0 << 5, +		[EN_ALDO234] = 0 << 4, +		[EN_ALDO5]   = 0 << 3, +		[EN_ALDO7]   = 0 << 2, +		[EN_DLDO7]   = 0 << 1, +		[EN_DLDO911] = 0 << 0, +	}; + +	switch (id) { +	case DLDO7: +		enable_id = EN_DLDO7; +		break; +	case DLDO9: +	case DLDO11: +		enable_id = EN_DLDO911; +		break; +	case ALDO1: +		enable_id = EN_ALDO1; +		break; +	case ALDO2 ... ALDO4: +		enable_id = EN_ALDO234; +		break; +	case ALDO5: +		enable_id = EN_ALDO5; +		break; +	case ALDO7: +		enable_id = EN_ALDO7; +		break; +	default: +		return 0; +	} + +	/* if no platform data for ldo pin, then set default enable mode */ +	if (!pdata || !pdata->ldo_pin || !pdata->ldo_pin[enable_id]) +		goto set_default_ldo_enable_mode; + +	ldo->en_pin = pdata->ldo_pin[enable_id]; + +	ret = lp8788_gpio_request_ldo_en(ldo, enable_id); +	if (ret) +		goto set_default_ldo_enable_mode; + +	return ret; + +set_default_ldo_enable_mode: +	return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], +				val[enable_id]); +} + +static __devinit int lp8788_dldo_probe(struct platform_device *pdev) +{ +	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); +	int id = pdev->id; +	struct lp8788_ldo *ldo; +	struct regulator_config cfg = { }; +	struct regulator_dev *rdev; +	int ret; + +	ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); +	if (!ldo) +		return -ENOMEM; + +	ldo->lp = lp; +	ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]); +	if (ret) +		return ret; + +	cfg.dev = lp->dev; +	cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; +	cfg.driver_data = ldo; +	cfg.regmap = lp->regmap; + +	rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); +	if (IS_ERR(rdev)) { +		ret = PTR_ERR(rdev); +		dev_err(lp->dev, "DLDO%d regulator register err = %d\n", +				id + 1, ret); +		return ret; +	} + +	ldo->regulator = rdev; +	platform_set_drvdata(pdev, ldo); + +	return 0; +} + +static int __devexit lp8788_dldo_remove(struct platform_device *pdev) +{ +	struct lp8788_ldo *ldo = platform_get_drvdata(pdev); + +	platform_set_drvdata(pdev, NULL); +	regulator_unregister(ldo->regulator); + +	return 0; +} + +static struct platform_driver lp8788_dldo_driver = { +	.probe = lp8788_dldo_probe, +	.remove = __devexit_p(lp8788_dldo_remove), +	.driver = { +		.name = LP8788_DEV_DLDO, +		.owner = THIS_MODULE, +	}, +}; + +static __devinit int lp8788_aldo_probe(struct platform_device *pdev) +{ +	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); +	int id = pdev->id; +	struct lp8788_ldo *ldo; +	struct regulator_config cfg = { }; +	struct regulator_dev *rdev; +	int ret; + +	ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); +	if (!ldo) +		return -ENOMEM; + +	ldo->lp = lp; +	ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]); +	if (ret) +		return ret; + +	cfg.dev = lp->dev; +	cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; +	cfg.driver_data = ldo; +	cfg.regmap = lp->regmap; + +	rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); +	if (IS_ERR(rdev)) { +		ret = PTR_ERR(rdev); +		dev_err(lp->dev, "ALDO%d regulator register err = %d\n", +				id + 1, ret); +		return ret; +	} + +	ldo->regulator = rdev; +	platform_set_drvdata(pdev, ldo); + +	return 0; +} + +static int __devexit lp8788_aldo_remove(struct platform_device *pdev) +{ +	struct lp8788_ldo *ldo = platform_get_drvdata(pdev); + +	platform_set_drvdata(pdev, NULL); +	regulator_unregister(ldo->regulator); + +	return 0; +} + +static struct platform_driver lp8788_aldo_driver = { +	.probe = lp8788_aldo_probe, +	.remove = __devexit_p(lp8788_aldo_remove), +	.driver = { +		.name = LP8788_DEV_ALDO, +		.owner = THIS_MODULE, +	}, +}; + +static int __init lp8788_ldo_init(void) +{ +	int ret; + +	ret = platform_driver_register(&lp8788_dldo_driver); +	if (ret) +		return ret; + +	return platform_driver_register(&lp8788_aldo_driver); +} +subsys_initcall(lp8788_ldo_init); + +static void __exit lp8788_ldo_exit(void) +{ +	platform_driver_unregister(&lp8788_aldo_driver); +	platform_driver_unregister(&lp8788_dldo_driver); +} +module_exit(lp8788_ldo_exit); + +MODULE_DESCRIPTION("TI LP8788 LDO Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-dldo"); +MODULE_ALIAS("platform:lp8788-aldo");  |