/* * 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");