From cbdb8f5916cf6512917a7fe2386b8701bbf7b728 Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Thu, 15 Oct 2015 15:26:58 +0900 Subject: [PATCH] LP8758 - consolidated version Signed-off-by: Daniel Jeong --- .../devicetree/bindings/regulator/lp8758.txt | 45 +- drivers/regulator/lp8758.c | 440 +++++++++++++----- include/linux/platform_data/lp8758.h | 101 ---- include/linux/regulator/lp872x.h | 90 ++++ include/linux/regulator/lp8758.h | 194 ++++++++ 5 files changed, 630 insertions(+), 240 deletions(-) delete mode 100644 include/linux/platform_data/lp8758.h create mode 100644 include/linux/regulator/lp872x.h create mode 100644 include/linux/regulator/lp8758.h diff --git a/Documentation/devicetree/bindings/regulator/lp8758.txt b/Documentation/devicetree/bindings/regulator/lp8758.txt index 979a1b0..70db03d 100644 --- a/Documentation/devicetree/bindings/regulator/lp8758.txt +++ b/Documentation/devicetree/bindings/regulator/lp8758.txt @@ -10,17 +10,30 @@ Example: compatible = "ti,lp8758"; reg = <0x60>; - /* BUCKx Pin Setting - 0: i2c control, - 1: EN1 Pin Enable/Disable control, - 2: EN1 Pin Roof/Floor control, - 3: EN2 Pin Enable/Disable control, - 4: EN2 Pin Roof/Floor control - */ - buck0_pinctrl = <0>; - buck1_pinctrl = <0>; - buck2_pinctrl = <0>; - buck3_pinctrl = <0>; + /* + * sub version info + * 0 : b0 + * 1 : d0 + * 2 : e0 + * 3 : f0 + */ + sub_version = <3>; + + /* + * Buck Control Setting + * buck_ctrl[0] = buck0 control setting + * buck_ctrl[1] = buck1 control setting + * buck_ctrl[2] = buck2 control setting + * buck_ctrl[3] = buck3 control setting + * setting values + * 0: i2c control, + * 1: EN1 Pin Enable/Disable control, + * 2: EN1 Pin Roof/Floor control, + * 3: EN2 Pin Enable/Disable control, + * 4: EN2 Pin Roof/Floor control + */ + buck_ctrl = <1 0 1 0>; + /* * The gpio for interrupt depends on the processor environment. * For example, following GPIO means GPIO60 in OMAP335x. @@ -35,6 +48,11 @@ Example: regulator-max-microamp = <5000000>; regulator-boot-on; }; + buck1 { + regulator-name = "lp8758-buck1"; + regulator-min-microamp = <1500000>; + regulator-max-microamp = <5000000>; + }; buck2 { regulator-name = "lp8758-buck2"; regulator-min-microvolt = <500000>; @@ -43,4 +61,9 @@ Example: regulator-max-microamp = <5000000>; regulator-boot-on; }; + buck3 { + regulator-name = "lp8758-buck3"; + regulator-min-microamp = <1500000>; + regulator-max-microamp = <5000000>; + }; }; diff --git a/drivers/regulator/lp8758.c b/drivers/regulator/lp8758.c index 523162c..dbe9e59 100644 --- a/drivers/regulator/lp8758.c +++ b/drivers/regulator/lp8758.c @@ -11,36 +11,28 @@ * */ -/******************************************************************** -Notice : - It is a preliminary version based on f0 for reference. - A consolidated verson will be released soon. -********************************************************************/ - - - -#include -#include #include +#include #include -#include #include -#include +#include #include #include -#include +#include #include +#include #include #include -#include +#include +#include struct lp8758_chip { struct device *dev; struct regmap *regmap; struct lp8758_platform_data *pdata; - int irq; struct regulator_dev *rdev[LP8758_BUCK_MAX]; + struct regulator_desc regulators[LP8758_BUCK_MAX]; }; /* voltage map */ @@ -88,22 +80,42 @@ static const unsigned int lp8758_current_limit_uA[] = { 1500000, 2000000, 2500000, 3000000, 3500000, 4000000, 4500000, 5000000 }; -static int lp8758_read(struct lp8758_chip *pchip, unsigned int reg, - unsigned int *val) -{ - return regmap_read(pchip->regmap, reg, val); +const static int sub_version_config[LP8758_SUB_VER_MAX][LP8758_BUCK_MAX] ={ + [LP8758_SUB_VER_B0] = { LP8758_BUCK_MASTER, LP8758_BUCK_SLAVE, + LP8758_BUCK_SLAVE, LP8758_BUCK_SLAVE }, + [LP8758_SUB_VER_D0] = { LP8758_BUCK_MASTER, LP8758_BUCK_SLAVE, + LP8758_BUCK_MASTER, LP8758_BUCK_MASTER }, + [LP8758_SUB_VER_E0] = { LP8758_BUCK_MASTER, LP8758_BUCK_MASTER, + LP8758_BUCK_MASTER, LP8758_BUCK_MASTER }, + [LP8758_SUB_VER_F0] = { LP8758_BUCK_MASTER, LP8758_BUCK_SLAVE, + LP8758_BUCK_MASTER, LP8758_BUCK_SLAVE } +}; + +static bool lp8758_is_master(struct lp8758_chip *pchip, enum lp8758_bucks buck) { + int ver = pchip->pdata->sub_version; + if(sub_version_config[ver][buck] == LP8758_BUCK_MASTER) + return true; + return false; } -static int lp8758_write(struct lp8758_chip *pchip, unsigned int reg, - unsigned int val) -{ - return regmap_write(pchip->regmap, reg, val); +static unsigned int lp8758_get_ctrl1_address(enum lp8758_bucks buck){ + unsigned int ctrl_register[LP8758_BUCK_MAX] = { + [LP8758_BUCK0] = LP8758_REG_BUCK0_CTRL1, + [LP8758_BUCK1] = LP8758_REG_BUCK1_CTRL1, + [LP8758_BUCK2] = LP8758_REG_BUCK2_CTRL1, + [LP8758_BUCK3] = LP8758_REG_BUCK3_CTRL1 + }; + return ctrl_register[buck]; } -static int lp8758_update_bits(struct lp8758_chip *pchip, unsigned int reg, - unsigned int mask, unsigned int val) -{ - return regmap_update_bits(pchip->regmap, reg, mask, val); +static unsigned int lp8758_get_ctrl2_address(enum lp8758_bucks buck){ + unsigned int ctrl_register[LP8758_BUCK_MAX] = { + [LP8758_BUCK0] = LP8758_REG_BUCK0_CTRL2, + [LP8758_BUCK1] = LP8758_REG_BUCK1_CTRL2, + [LP8758_BUCK2] = LP8758_REG_BUCK2_CTRL2, + [LP8758_BUCK3] = LP8758_REG_BUCK3_CTRL2 + }; + return ctrl_register[buck]; } static int lp8758_buck_set_current_limit(struct regulator_dev *rdev, @@ -112,24 +124,17 @@ static int lp8758_buck_set_current_limit(struct regulator_dev *rdev, struct lp8758_chip *pchip = rdev_get_drvdata(rdev); enum lp8758_bucks buck = rdev_get_id(rdev); int icnt; - u8 addr; - - switch (buck) { - case LP8758_BUCK0: - addr = LP8758_REG_BUCK0_CTRL2; - break; - case LP8758_BUCK2: - addr = LP8758_REG_BUCK2_CTRL2; - break; - default: + + if(buck > LP8758_BUCK_MAX-1) return -EINVAL; - } for (icnt = ARRAY_SIZE(lp8758_current_limit_uA) - 1; icnt >= 0; icnt--) { if (lp8758_current_limit_uA[icnt] >= min_uA && - lp8758_current_limit_uA[icnt] <= max_uA) - return lp8758_update_bits(pchip, addr, - LP8758_ILIM_MASK, icnt << LP8758_ILIM_SHIFT); + lp8758_current_limit_uA[icnt] <= max_uA){ + return regmap_update_bits(pchip->regmap, + lp8758_get_ctrl2_address(buck), + LP8758_ILIM_MASK, icnt << LP8758_ILIM_SHIFT); + } } return -EINVAL; @@ -139,22 +144,13 @@ static int lp8758_buck_get_current_limit(struct regulator_dev *rdev) { struct lp8758_chip *pchip = rdev_get_drvdata(rdev); enum lp8758_bucks buck = rdev_get_id(rdev); - u8 addr; unsigned int val; int ret; - - switch (buck) { - case LP8758_BUCK0: - addr = LP8758_REG_BUCK0_CTRL2; - break; - case LP8758_BUCK2: - addr = LP8758_REG_BUCK2_CTRL2; - break; - default: + + if(buck > LP8758_BUCK_MAX-1) return -EINVAL; - } - ret = lp8758_read(pchip, addr, &val); + ret = regmap_read(pchip->regmap, lp8758_get_ctrl2_address(buck), &val); if (ret) return ret; @@ -168,23 +164,20 @@ static int lp8758_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct lp8758_chip *pchip = rdev_get_drvdata(rdev); enum lp8758_bucks buck = rdev_get_id(rdev); - u8 addr; - - switch (buck) { - case LP8758_BUCK0: - addr = LP8758_REG_BUCK0_CTRL1; - break; - case LP8758_BUCK2: - addr = LP8758_REG_BUCK2_CTRL1; - break; - default: + unsigned int addr; + + if(buck > LP8758_BUCK_MAX-1) return -EINVAL; - } + addr = lp8758_get_ctrl1_address(buck); if (mode == REGULATOR_MODE_FAST) - return lp8758_update_bits(pchip, addr, 0x02, 0x02); + return regmap_update_bits(pchip->regmap, addr, + LP8758_BUCK_OP_MODE_MASK, + LP8758_BUCK_OP_FPWM); else if (mode == REGULATOR_MODE_NORMAL) - return lp8758_update_bits(pchip, addr, 0x02, 0x00); + return regmap_update_bits(pchip->regmap, addr, + LP8758_BUCK_OP_MODE_MASK, + LP8758_BUCK_OP_AUTO); else return -EINVAL; } @@ -194,28 +187,69 @@ static unsigned int lp8758_buck_get_mode(struct regulator_dev *rdev) struct lp8758_chip *pchip = rdev_get_drvdata(rdev); enum lp8758_bucks buck = rdev_get_id(rdev); unsigned int val; - u8 addr; int ret; - switch (buck) { - case LP8758_BUCK0: - addr = LP8758_REG_BUCK0_CTRL1; - break; - case LP8758_BUCK2: - addr = LP8758_REG_BUCK2_CTRL1; - break; - default: + if(buck > LP8758_BUCK_MAX-1) return -EINVAL; - } - ret = lp8758_read(pchip, addr, &val); + ret = regmap_read(pchip->regmap, lp8758_get_ctrl1_address(buck), &val); if (ret) return ret; - return val & 0x02 ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; + return (val & LP8758_BUCK_OP_MODE_MASK) + ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static int lp8758_buck_set_ramp(struct regulator_dev *rdev, int ramp) +{ + int ret = -EINVAL; + unsigned int regval = 0x00; + enum lp8758_bucks buck = rdev_get_id(rdev); + struct lp8758_chip *pchip = rdev_get_drvdata(rdev); + + if(buck > LP8758_BUCK_MAX-1) + return -EINVAL; + + if(lp8758_is_master(pchip,buck)) { + /* uV/us */ + switch (ramp) { + case 0 ... 470: + regval = 0x07; + break; + case 471 ... 940: + regval = 0x06; + break; + case 941 ... 1900: + regval = 0x05; + break; + case 1901 ... 3800: + regval = 0x04; + break; + case 3801 ... 7500: + regval = 0x03; + break; + case 7501 ... 10000: + regval = 0x02; + break; + case 10001 ... 15000: + regval = 0x01; + break; + case 15001 ... 30000: + regval = 0x00; + break; + default: + dev_err(pchip->dev, + "Not supported ramp value %d %s\n", ramp, __func__); + return -EINVAL; + } + ret = regmap_update_bits(pchip->regmap, lp8758_get_ctrl2_address(buck), + LP8758_BUCK_RAMP_MASK, regval); + } + return ret; } -static struct regulator_ops lp8758_buck_ops = { +/* regulator operation when it is set to master */ +static struct regulator_ops lp8758_buck_master_ops = { .map_voltage = regulator_map_voltage_ascend, .list_voltage = regulator_list_voltage_table, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -227,38 +261,138 @@ static struct regulator_ops lp8758_buck_ops = { .get_mode = lp8758_buck_get_mode, .set_current_limit = lp8758_buck_set_current_limit, .get_current_limit = lp8758_buck_get_current_limit, + .set_ramp_delay = lp8758_buck_set_ramp, +}; + +/* regulator operation when it is tied to another as slave */ +static struct regulator_ops lp8758_buck_slave_ops = { + .set_current_limit = lp8758_buck_set_current_limit, + .get_current_limit = lp8758_buck_get_current_limit, }; -static struct regulator_desc lp8758_regulators[LP8758_BUCK_MAX] = { +#define lp8758_rail(_id) "lp8755-buck"#_id +/* regulator description when it is set to master */ +#define lp8758_buck_master_desc(_id)\ +{\ + .name = lp8758_rail(_id),\ + .id = LP8758_BUCK##_id,\ + .ops = &lp8758_buck_master_ops,\ + .n_voltages = ARRAY_SIZE(lp8758_buck_voltage_map),\ + .volt_table = lp8758_buck_voltage_map,\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .enable_reg = LP8758_REG_BUCK##_id##_CTRL1,\ + .enable_mask = LP8758_BUCK_EN_MASK,\ + .vsel_reg = LP8758_REG_BUCK##_id##_VOUT,\ + .vsel_mask = LP8758_BUCK_VOUT_MASK,\ +} + +/* regulator description when it is set to master and roof/floor control */ +#define lp8758_buck_master_roof_floor_desc(_id)\ +{\ + .name = lp8758_rail(_id),\ + .id = LP8758_BUCK##_id,\ + .ops = &lp8758_buck_master_ops,\ + .n_voltages = ARRAY_SIZE(lp8758_buck_voltage_map),\ + .volt_table = lp8758_buck_voltage_map,\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .enable_reg = LP8758_REG_BUCK##_id##_CTRL1,\ + .enable_mask = LP8758_BUCK_EN_MASK,\ + .vsel_reg = LP8758_REG_BUCK##_id##_FLOORVOUT,\ + .vsel_mask = LP8758_BUCK_VOUT_MASK,\ +} + +/* regulator description when it is tied to another as slave */ +#define lp8758_buck_slave_desc(_id)\ +{\ + .name = lp8758_rail(_id),\ + .id = LP8758_BUCK##_id,\ + .ops = &lp8758_buck_slave_ops,\ + .type = REGULATOR_CURRENT,\ + .owner = THIS_MODULE,\ +} + +/* regulators description for all configuration */ +static struct regulator_desc lp8758_buck_master_config[LP8758_BUCK_MAX][LP8758_CTRL_MAX] = { + { + [LP8758_CTRL_MODE0] = lp8758_buck_master_desc(0), + [LP8758_CTRL_MODE1] = lp8758_buck_master_desc(0), + [LP8758_CTRL_MODE2] = lp8758_buck_master_roof_floor_desc(0), + [LP8758_CTRL_MODE3] = lp8758_buck_master_desc(0), + [LP8758_CTRL_MODE4] = lp8758_buck_master_roof_floor_desc(0) + }, { - .name = "lp8758-buck0", - .id = LP8758_BUCK0, - .ops = &lp8758_buck_ops, - .n_voltages = ARRAY_SIZE(lp8758_buck_voltage_map), - .volt_table = lp8758_buck_voltage_map, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - .enable_reg = LP8758_REG_BUCK0_CTRL1, - .enable_mask = LP8758_BUCK_EN_MASK, - .vsel_reg = LP8758_REG_BUCK0_VOUT, - .vsel_mask = LP8758_BUCK_VOUT_MASK, + [LP8758_CTRL_MODE0] = lp8758_buck_master_desc(1), + [LP8758_CTRL_MODE1] = lp8758_buck_master_desc(1), + [LP8758_CTRL_MODE2] = lp8758_buck_master_roof_floor_desc(1), + [LP8758_CTRL_MODE3] = lp8758_buck_master_desc(1), + [LP8758_CTRL_MODE4] = lp8758_buck_master_roof_floor_desc(1) }, { - .name = "lp8758-buck2", - .id = LP8758_BUCK2, - .ops = &lp8758_buck_ops, - .n_voltages = ARRAY_SIZE(lp8758_buck_voltage_map), - .volt_table = lp8758_buck_voltage_map, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - .enable_reg = LP8758_REG_BUCK2_CTRL1, - .enable_mask = LP8758_BUCK_EN_MASK, - .vsel_reg = LP8758_REG_BUCK2_VOUT, - .vsel_mask = LP8758_BUCK_VOUT_MASK, + [LP8758_CTRL_MODE0] = lp8758_buck_master_desc(2), + [LP8758_CTRL_MODE1] = lp8758_buck_master_desc(2), + [LP8758_CTRL_MODE2] = lp8758_buck_master_roof_floor_desc(2), + [LP8758_CTRL_MODE3] = lp8758_buck_master_desc(2), + [LP8758_CTRL_MODE4] = lp8758_buck_master_roof_floor_desc(2) + }, + { + [LP8758_CTRL_MODE0] = lp8758_buck_master_desc(3), + [LP8758_CTRL_MODE1] = lp8758_buck_master_desc(3), + [LP8758_CTRL_MODE2] = lp8758_buck_master_roof_floor_desc(3), + [LP8758_CTRL_MODE3] = lp8758_buck_master_desc(3), + [LP8758_CTRL_MODE4] = lp8758_buck_master_roof_floor_desc(3) } }; -static int lp8758_regulator_init(struct lp8758_chip *pchip) +static struct regulator_desc lp8758_buck_slave_config[LP8758_BUCK_MAX] = { + lp8758_buck_slave_desc(0), + lp8758_buck_slave_desc(1), + lp8758_buck_slave_desc(2), + lp8758_buck_slave_desc(3) +}; + +/* + * select regulator description for each buck + * and write configuration value into control register + */ +static int lp8758_regulator_init(struct lp8758_chip *pchip){ + int icnt, ret, bctrl_mode; + struct regulator_desc *reg; + + if(pchip->pdata->sub_version > LP8758_SUB_VER_MAX-1) + return -EINVAL; + + /* select regulator description based on sub version*/ + for(icnt = LP8758_BUCK0 ; icnt < LP8758_BUCK_MAX; icnt++){ + /* select regulator description based on sub version & control mode */ + if(lp8758_is_master(pchip,icnt)) { + bctrl_mode = pchip->pdata->buck_ctrl[icnt]; + if(bctrl_mode > LP8758_CTRL_MAX-1) + return -EINVAL; + reg = &lp8758_buck_master_config[icnt][bctrl_mode]; + + /* control registser set */ + if(bctrl_mode != LP8758_CTRL_MODE0) + bctrl_mode = (bctrl_mode - 1) | LP8758_CTRL_PIN_EN_MASK; + + ret = regmap_update_bits(pchip->regmap, lp8758_get_ctrl1_address(icnt), + LP8758_CTRL_BUCK_MASK, + bctrl_mode << LP8758_CTRL_BUCK_SHIFT); + if(ret < 0){ + dev_err(pchip->dev, "lp8758 %s i2c error \n",__func__); + return ret; + } + } else { + reg = &lp8758_buck_slave_config[icnt], + dev_err(pchip->dev, "lp8758 %d regulator is SLAVE\n",icnt); + } + memcpy(&pchip->regulators[icnt], reg, sizeof(struct regulator_desc)); + } + return 0; +} + +static int lp8758_regulator_register(struct lp8758_chip *pchip) { int ret, icnt; struct lp8758_platform_data *pdata = pchip->pdata; @@ -273,7 +407,7 @@ static int lp8758_regulator_init(struct lp8758_chip *pchip) rconfig.of_node = pchip->dev->of_node; pchip->rdev[icnt] = devm_regulator_register(pchip->dev, - &lp8758_regulators[icnt], &rconfig); + &pchip->regulators[icnt], &rconfig); if (IS_ERR(pchip->rdev[icnt])) { ret = PTR_ERR(pchip->rdev[icnt]); pchip->rdev[icnt] = NULL; @@ -281,7 +415,6 @@ static int lp8758_regulator_init(struct lp8758_chip *pchip) "regulator init failed: buck %d\n", icnt); return ret; } - dev_info(pchip->dev, "lp8758 regulator %d\n is registered",icnt); } return 0; } @@ -289,20 +422,53 @@ static int lp8758_regulator_init(struct lp8758_chip *pchip) static irqreturn_t lp8758_irq_handler(int irq, void *data) { int ret, icnt; - unsigned int int_top; + unsigned int int_top, rdata; struct lp8758_chip *pchip = data; - ret = lp8758_read(pchip, LP8758_REG_INT_TOP, &int_top); - if(int_top & LP8758_OVERTEMP_MASK) + ret = regmap_read(pchip->regmap, LP8758_REG_INT_TOP, &int_top); + if(int_top & LP8758_INT_TMEP_MASK) for(icnt = LP8758_BUCK0; icnt < LP8758_BUCK_MAX; icnt++) regulator_notifier_call_chain(pchip->rdev[icnt], REGULATOR_EVENT_OVER_TEMP, NULL); - lp8758_write(pchip, LP8758_REG_INT_BUCK_0_1, 0x77); - lp8758_write(pchip, LP8758_REG_INT_BUCK_2_3, 0x77); - lp8758_write(pchip, LP8758_REG_INT_TOP, 0x0f); + if(int_top & LP8758_INT_BUCK01_MASK) { + ret = regmap_read(pchip->regmap, LP8758_REG_INT_BUCK_01, &rdata); + if(rdata & LP8758_INT_OVC_BUCK0_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK0], + LP8758_EVENT_OCP, NULL); + if(rdata & LP8758_INT_OVC_BUCK1_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK1], + LP8758_EVENT_OCP, NULL); + if(rdata & LP8758_INT_PWR_FAULT_BUCK0_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK0], + LP8758_EVENT_PWR_FAULT, NULL); + if(rdata & LP8758_INT_PWR_FAULT_BUCK1_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK1], + LP8758_EVENT_PWR_FAULT, NULL); + } + + if(int_top & LP8758_INT_BUCK23_MASK) { + ret = regmap_read(pchip->regmap, LP8758_REG_INT_BUCK_23, &rdata); + if(rdata & LP8758_INT_OVC_BUCK2_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK2], + LP8758_EVENT_OCP, NULL); + if(rdata & LP8758_INT_OVC_BUCK3_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK3], + LP8758_EVENT_OCP, NULL); + if(rdata & LP8758_INT_PWR_FAULT_BUCK2_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK2], + LP8758_EVENT_PWR_FAULT, NULL); + if(rdata & LP8758_INT_PWR_FAULT_BUCK3_MASK) + regulator_notifier_call_chain(pchip->rdev[LP8758_BUCK3], + LP8758_EVENT_PWR_FAULT, NULL); + } + + /* clear interrupt */ + regmap_write(pchip->regmap, LP8758_REG_INT_BUCK_01, LP8758_INT_CLEAR_BUCK); + regmap_write(pchip->regmap, LP8758_REG_INT_BUCK_23, LP8758_INT_CLEAR_BUCK); + regmap_write(pchip->regmap, LP8758_REG_INT_TOP, LP8758_INT_CLEAR_TOP); - dev_info(pchip->dev, "lp8758 IRQ Handeled"); + dev_err(pchip->dev, "lp8758 IRQ Handeled"); return IRQ_HANDLED; } @@ -310,17 +476,18 @@ static int lp8758_intr_config(struct lp8758_chip *pchip) { int ret, irq; - if (pchip->irq == 0) { + if (pchip->pdata->irq == 0) { dev_warn(pchip->dev, "not use interrupt : %s\n", __func__); return 0; } - lp8758_write(pchip, LP8758_REG_INT_BUCK_0_1, 0x77); - lp8758_write(pchip, LP8758_REG_INT_BUCK_2_3, 0x77); - lp8758_write(pchip, LP8758_REG_INT_TOP, 0x0f); + /* initially clear interrupt */ + regmap_write(pchip->regmap, LP8758_REG_INT_BUCK_01, LP8758_INT_CLEAR_BUCK); + regmap_write(pchip->regmap, LP8758_REG_INT_BUCK_23, LP8758_INT_CLEAR_BUCK); + regmap_write(pchip->regmap, LP8758_REG_INT_TOP, LP8758_INT_CLEAR_TOP); - gpio_request_one(pchip->irq, GPIOF_DIR_IN,"lp8758-irq"); - irq = gpio_to_irq(pchip->irq); + gpio_request_one(pchip->pdata->irq, GPIOF_DIR_IN,"lp8758-irq"); + irq = gpio_to_irq(pchip->pdata->irq); if(irq < 0){ dev_warn(pchip->dev, "irq can't be configurated\n"); return -EINVAL; @@ -329,22 +496,21 @@ static int lp8758_intr_config(struct lp8758_chip *pchip) ret = request_threaded_irq(irq, NULL, lp8758_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lp8758-irq", pchip); - dev_info(pchip->dev, "irq config is configured gpio %d irq %d\n", - pchip->irq, irq); - return ret; } static struct of_regulator_match lp8758_matches[LP8758_BUCK_MAX] = { { .name = "buck0", .driver_data = (void *)LP8758_BUCK0, }, + { .name = "buck1", .driver_data = (void *)LP8758_BUCK1, }, { .name = "buck2", .driver_data = (void *)LP8758_BUCK2, }, + { .name = "buck3", .driver_data = (void *)LP8758_BUCK3, }, }; static int lp8758_parse_dt(struct i2c_client *client, struct lp8758_chip *pchip) { struct device_node *node = client->dev.of_node; - int count, icnt; + int err, icnt; pchip->pdata = devm_kzalloc(&client->dev, sizeof(struct lp8758_platform_data), GFP_KERNEL); @@ -353,17 +519,31 @@ static int lp8758_parse_dt(struct i2c_client *client, return -ENOMEM; } - count = of_regulator_match(&client->dev, node, + err = of_regulator_match(&client->dev, node, lp8758_matches, LP8758_BUCK_MAX); - if (count <= 0) + if (err <= 0){ dev_err(&client->dev, "lp8758 --ERR - of regulator match\n"); + return -EINVAL; + } for(icnt = 0; icnt < LP8758_BUCK_MAX; icnt++){ pchip->pdata->buck_data[icnt] = lp8758_matches[icnt].init_data; } - pchip->irq = of_get_named_gpio(node,"irq-gpio", 0); - + pchip->pdata->irq = of_get_named_gpio(node,"irq-gpio", 0); + err = of_property_read_u32(node, "sub_version", + &pchip->pdata->sub_version); + if(err < 0){ + dev_err(&client->dev, "lp8758 --ERR - of chip version read\n"); + return -EINVAL; + } + + err = of_property_read_u32_array(node, "buck_ctrl", + pchip->pdata->buck_ctrl, LP8758_BUCK_MAX); + if(err < 0){ + dev_err(&client->dev, "lp8758 --ERR - pin ctrl data\n"); + return -EINVAL; + } return 0; } @@ -384,7 +564,6 @@ static int lp8758_probe(struct i2c_client *client, struct lp8758_chip *pchip; int ret = 0; - dev_info(&client->dev, "lp8758 module probe\n"); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "i2c functionality check fail.\n"); return -EOPNOTSUPP; @@ -405,7 +584,6 @@ static int lp8758_probe(struct i2c_client *client, ret = lp8758_parse_dt(client, pchip); if(ret < 0) return ret; - pchip->dev = &client->dev; i2c_set_clientdata(client, pchip); @@ -415,6 +593,12 @@ static int lp8758_probe(struct i2c_client *client, return ret; } + ret = lp8758_regulator_register(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to register regulators\n"); + return ret; + } + ret = lp8758_intr_config(pchip); if (ret < 0) { dev_err(&client->dev, "fail to irq config\n"); diff --git a/include/linux/platform_data/lp8758.h b/include/linux/platform_data/lp8758.h deleted file mode 100644 index 8877a35..0000000 --- a/include/linux/platform_data/lp8758.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Simple driver for Texas Instruments lp8758 Regulator chip - * Copyright (C) 2015 Texas Instruments - * - * 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. - * - */ - -#ifndef __LINUX_LP8758_H -#define __LINUX_LP8758_H - -#include - -#define LP8758_NAME "lp8758" -#define LP8758_ADDR 0x60 - -enum lp8758_bucks { - LP8758_BUCK0 = 0, - LP8758_BUCK2, - LP8758_BUCK_MAX -}; - -enum lp8758_registers { - LP8758_REG_DEV_REV = 0x00, - LP8758_REG_OTP_REV = 0x01, - LP8758_REG_BUCK0_CTRL1 = 0x02, - LP8758_REG_BUCK0_CTRL2 = 0x03, - LP8758_REG_BUCK1_CTRL1 = 0x04, - LP8758_REG_BUCK1_CTRL2 = 0x05, - LP8758_REG_BUCK2_CTRL1 = 0x06, - LP8758_REG_BUCK2_CTRL2 = 0x07, - LP8758_REG_BUCK3_CTRL1 = 0x08, - LP8758_REG_BUCK3_CTRL2 = 0x09, - LP8758_REG_BUCK0_VOUT = 0x0a, - LP8758_REG_BUCK0_FLOORVOUT = 0x0b, - LP8758_REG_BUCK1_VOUT = 0x0c, - LP8758_REG_BUCK1_FLOORVOUT = 0x0d, - LP8758_REG_BUCK2_VOUT = 0x0e, - LP8758_REG_BUCK2_FLOORVOUT = 0x0f, - LP8758_REG_BUCK3_VOUT = 0x10, - LP8758_REG_BUCK3_FLOORVOUT = 0x11, - LP8758_REG_BUCK0_DELAY = 0x12, - LP8758_REG_BUCK1_DELAY = 0x13, - LP8758_REG_BUCK2_DELAY = 0x14, - LP8758_REG_BUCK3_DELAY = 0x15, - LP8758_REG_RESET = 0x16, - LP8758_REG_CONFIG = 0x17, - LP8758_REG_INT_TOP = 0x18, - LP8758_REG_INT_BUCK_0_1 = 0x19, - LP8758_REG_INT_BUCK_2_3 = 0x1a, - LP8758_REG_STAT_TOP = 0x1b, - LP8758_REG_STAT_BUCK_0_1 = 0x1c, - LP8758_REG_STAT_BUCK_2_3 = 0x1d, - LP8758_REG_MASK_TOP = 0x1e, - LP8758_REG_MASK_BUCK_0_1 = 0x1f, - LP8758_REG_MASK_BUCK_2_3 = 0x20, - LP8758_REG_SEL_I_LOAD = 0x21, - LP8758_REG_SEL_I_LOAD_2 = 0x22, - LP8758_REG_SEL_I_LOAD_1 = 0x23, - LP8758_REG_MAX = 0xff -}; - -#define LP8758_BUCK_EN_MASK 0x80 -#define LP8758_BUCK_VOUT_MASK 0xff - -/* - * PWR FAULT : power fault detected - * OCP : over current protect activated - * OVP : over voltage protect activated - * TEMP_WARN : thermal warning - * TEMP_SHDN : thermal shutdonw detected - * I_LOAD : current measured - */ -#define LP8758_EVENT_PWR_FAULT REGULATOR_EVENT_FAIL -#define LP8758_EVENT_OCP REGULATOR_EVENT_OVER_CURRENT -#define LP8758_EVENT_OVP 0x10000 -#define LP8758_EVENT_TEMP_WARN 0x2000 -#define LP8758_EVENT_TEMP_SHDN REGULATOR_EVENT_OVER_TEMP -#define LP8758_EVENT_I_LOAD 0x40000 - -#define LP8758_BUCK0INT_MASK 0x10 -#define LP8758_BUCK1INT_MASK 0x20 -#define LP8758_BUCK2INT_MASK 0x40 -#define LP8758_BUCK3INT_MASK 0x80 -#define LP8758_OVERTEMP_MASK 0x08 -#define LP8758_OVERCURRENT_MASK 0x01 - -#define LP8758_ILIM_MASK 0x38 -#define LP8758_ILIM_SHIFT 3 - -/* struct lp8758 platform data - * @buck_data : buck0~6 init voltage in uV - */ -struct lp8758_platform_data { - - struct regulator_init_data *buck_data[LP8758_BUCK_MAX]; -}; - -#endif /* __LINUX_LP8758_H */ diff --git a/include/linux/regulator/lp872x.h b/include/linux/regulator/lp872x.h new file mode 100644 index 0000000..132e05c --- /dev/null +++ b/include/linux/regulator/lp872x.h @@ -0,0 +1,90 @@ +/* + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * 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. + * + */ + +#ifndef __LP872X_REGULATOR_H__ +#define __LP872X_REGULATOR_H__ + +#include +#include +#include + +#define LP872X_MAX_REGULATORS 9 + +enum lp872x_regulator_id { + LP8720_ID_BASE, + LP8720_ID_LDO1 = LP8720_ID_BASE, + LP8720_ID_LDO2, + LP8720_ID_LDO3, + LP8720_ID_LDO4, + LP8720_ID_LDO5, + LP8720_ID_BUCK, + + LP8725_ID_BASE, + LP8725_ID_LDO1 = LP8725_ID_BASE, + LP8725_ID_LDO2, + LP8725_ID_LDO3, + LP8725_ID_LDO4, + LP8725_ID_LDO5, + LP8725_ID_LILO1, + LP8725_ID_LILO2, + LP8725_ID_BUCK1, + LP8725_ID_BUCK2, + + LP872X_ID_MAX, +}; + +enum lp872x_dvs_state { + DVS_LOW = GPIOF_OUT_INIT_LOW, + DVS_HIGH = GPIOF_OUT_INIT_HIGH, +}; + +enum lp872x_dvs_sel { + SEL_V1, + SEL_V2, +}; + +/** + * lp872x_dvs + * @gpio : gpio pin number for dvs control + * @vsel : dvs selector for buck v1 or buck v2 register + * @init_state : initial dvs pin state + */ +struct lp872x_dvs { + int gpio; + enum lp872x_dvs_sel vsel; + enum lp872x_dvs_state init_state; +}; + +/** + * lp872x_regdata + * @id : regulator id + * @init_data : init data for each regulator + */ +struct lp872x_regulator_data { + enum lp872x_regulator_id id; + struct regulator_init_data *init_data; +}; + +/** + * lp872x_platform_data + * @general_config : the value of LP872X_GENERAL_CFG register + * @update_config : if LP872X_GENERAL_CFG register is updated, set true + * @regulator_data : platform regulator id and init data + * @dvs : dvs data for buck voltage control + */ +struct lp872x_platform_data { + u8 general_config; + bool update_config; + struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS]; + struct lp872x_dvs *dvs; +}; + +#endif diff --git a/include/linux/regulator/lp8758.h b/include/linux/regulator/lp8758.h new file mode 100644 index 0000000..ed2dc14 --- /dev/null +++ b/include/linux/regulator/lp8758.h @@ -0,0 +1,194 @@ +/* + * Simple driver for Texas Instruments lp8758 Regulator chip + * Copyright (C) 2015 Texas Instruments + * + * 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. + * + */ + +#ifndef __LINUX_LP8758_H +#define __LINUX_LP8758_H + +#include + +#define LP8758_NAME "lp8758" +#define LP8758_ADDR 0x60 + +enum lp8758_otp_id { + LP8758_B0 = 0xb0, + LP8758_D0 = 0xd0, + LP8758_E0 = 0xe0, + LP8758_F0 = 0xf0 +}; + +enum lp8758_sub_version { + LP8758_SUB_VER_B0 = 0, + LP8758_SUB_VER_D0, + LP8758_SUB_VER_E0, + LP8758_SUB_VER_F0, + LP8758_SUB_VER_MAX +}; + +enum lp8758_bucks { + LP8758_BUCK0 = 0, + LP8758_BUCK1, + LP8758_BUCK2, + LP8758_BUCK3, + LP8758_BUCK_MAX +}; + +/* + * MODE0 : Pin Ctrl disable + * MODE1 : Pin1 Ctrl + Enable/Disable + * MODE2 : Pin1 Ctrl + Roof/Floor + * MODE3 : Pin2 Ctrl + Enable/Diasble + * MODE4 : Pin2 Ctrl + Roof/Floor + */ +enum lp8758_ctrl_mode { + LP8758_CTRL_MODE0 = 0, + LP8758_CTRL_MODE1, + LP8758_CTRL_MODE2, + LP8758_CTRL_MODE3, + LP8758_CTRL_MODE4, + LP8758_CTRL_MAX +}; + +enum lp8758_buck_mode { + LP8758_BUCK_MASTER = 0, + LP8758_BUCK_SLAVE +}; + +enum lp8758_op_mode { + LP8758_BUCK_OP_AUTO = 0x00, + LP8758_BUCK_OP_FPWM = 0x02, +}; + +enum lp8758_registers { + LP8758_REG_DEV_REV = 0x00, + LP8758_REG_OTP_REV = 0x01, + LP8758_REG_BUCK0_CTRL1 = 0x02, + LP8758_REG_BUCK0_CTRL2 = 0x03, + LP8758_REG_BUCK1_CTRL1 = 0x04, + LP8758_REG_BUCK1_CTRL2 = 0x05, + LP8758_REG_BUCK2_CTRL1 = 0x06, + LP8758_REG_BUCK2_CTRL2 = 0x07, + LP8758_REG_BUCK3_CTRL1 = 0x08, + LP8758_REG_BUCK3_CTRL2 = 0x09, + LP8758_REG_BUCK0_VOUT = 0x0a, + LP8758_REG_BUCK0_FLOORVOUT = 0x0b, + LP8758_REG_BUCK1_VOUT = 0x0c, + LP8758_REG_BUCK1_FLOORVOUT = 0x0d, + LP8758_REG_BUCK2_VOUT = 0x0e, + LP8758_REG_BUCK2_FLOORVOUT = 0x0f, + LP8758_REG_BUCK3_VOUT = 0x10, + LP8758_REG_BUCK3_FLOORVOUT = 0x11, + LP8758_REG_BUCK0_DELAY = 0x12, + LP8758_REG_BUCK1_DELAY = 0x13, + LP8758_REG_BUCK2_DELAY = 0x14, + LP8758_REG_BUCK3_DELAY = 0x15, + LP8758_REG_RESET = 0x16, + LP8758_REG_CONFIG = 0x17, + LP8758_REG_INT_TOP = 0x18, + LP8758_REG_INT_BUCK_01 = 0x19, + LP8758_REG_INT_BUCK_23 = 0x1a, + LP8758_REG_STAT_TOP = 0x1b, + LP8758_REG_STAT_BUCK_01 = 0x1c, + LP8758_REG_STAT_BUCK_23 = 0x1d, + LP8758_REG_MASK_TOP = 0x1e, + LP8758_REG_MASK_BUCK_01 = 0x1f, + LP8758_REG_MASK_BUCK_23 = 0x20, + LP8758_REG_SEL_I_LOAD = 0x21, + LP8758_REG_SEL_I_LOAD_2 = 0x22, + LP8758_REG_SEL_I_LOAD_1 = 0x23, + LP8758_REG_MAX = 0xff +}; + +/* + * PWR FAULT : power fault detected + * OCP : over current protect activated + * OVP : over voltage protect activated + * TEMP_WARN : thermal warning + * TEMP_SHDN : thermal shutdonw detected + * I_LOAD : current measured + */ +#define LP8758_EVENT_PWR_FAULT REGULATOR_EVENT_FAIL +#define LP8758_EVENT_OCP REGULATOR_EVENT_OVER_CURRENT +#define LP8758_EVENT_OVP 0x10000 +#define LP8758_EVENT_TEMP_WARN 0x2000 +#define LP8758_EVENT_TEMP_SHDN REGULATOR_EVENT_OVER_TEMP +#define LP8758_EVENT_I_LOAD 0x40000 + +#define LP8758_INT_BUCK01_MASK 0x30 +#define LP8758_INT_BUCK23_MASK 0xc0 +#define LP8758_INT_TEMP_SHDN_MASK 0x08 +#define LP8758_INT_TEMP_WARN_MASK 0x04 + +/* Over Current interrupt mask */ +#define LP8758_INT_OVC_BUCK0_MASK 0x01 +#define LP8758_INT_OVC_BUCK1_MASK 0x10 +#define LP8758_INT_OVC_BUCK2_MASK 0x01 +#define LP8758_INT_OVC_BUCK3_MASK 0x10 +/* Short Circuit interrupt mask */ +#define LP8758_INT_SC_BUCK0_MASK 0x02 +#define LP8758_INT_SC_BUCK1_MASK 0x20 +#define LP8758_INT_SC_BUCK2_MASK 0x02 +#define LP8758_INT_SC_BUCK3_MASK 0x20 +/* Power Ground Reach interrupt mask */ +#define LP8758_INT_PG_BUCK0_MASK 0x04 +#define LP8758_INT_PG_BUCK1_MASK 0x40 +#define LP8758_INT_PG_BUCK2_MASK 0x04 +#define LP8758_INT_PG_BUCK3_MASK 0x40 + +#define LP8758_INT_TMEP_MASK\ + (LP8758_INT_TEMP_WARN_MASK | LP8758_INT_TEMP_SHDN_MASK) +#define LP8758_INT_PWR_FAULT_BUCK0_MASK\ + (LP8758_INT_SC_BUCK0_MASK | LP8758_INT_SC_BUCK0_MASK) +#define LP8758_INT_PWR_FAULT_BUCK1_MASK\ + (LP8758_INT_SC_BUCK1_MASK | LP8758_INT_SC_BUCK1_MASK) +#define LP8758_INT_PWR_FAULT_BUCK2_MASK\ + (LP8758_INT_SC_BUCK2_MASK | LP8758_INT_SC_BUCK2_MASK) +#define LP8758_INT_PWR_FAULT_BUCK3_MASK\ + (LP8758_INT_SC_BUCK3_MASK | LP8758_INT_SC_BUCK3_MASK) + +#define LP8758_INT_CLEAR_TOP 0x0f +#define LP8758_INT_CLEAR_BUCK 0x77 + +#define LP8758_ILIM_MASK 0x38 +#define LP8758_ILIM_SHIFT 3 + +#define LP8758_BUCK_EN_MASK 0x80 +#define LP8758_BUCK_VOUT_MASK 0xff + +#define LP8758_CTRL_BUCK_MASK 0x70 +#define LP8758_CTRL_BUCK_SHIFT 4 +#define LP8758_CTRL_PIN_EN_MASK 0x04 + +#define LP8758_BUCK_RAMP_MASK 0x07 +#define LP8758_BUCK_OP_MODE_MASK 0x04 + +/* + * struct lp8758 platform data + * @irq : irq number + * @sub_version : otp version 0-b0, 1-d0, 2-e0, 3-f0 + * @buck_ctrl[] : [0] buck0 buck control config. + * [1] buck1 buck control config. + * [2] buck2 buck control config. + * [3] buck3 buck control config. + * control config + * : 0 - EN_BUCK bit only + * : 1 - EN_BUCK bit & EN_PIN1 ENABLE/DISABLE + * : 2 - EN_BUCK bit & EN_PIN1 ROOF/FLOOR + * : 3 - EN_BUCK bit & EN_PIN2 ENABLE/DISABLE + * : 4 - EN_BUCK bit & EN_PIN2 ROOF/FLOOR + * @buck_data : init buck data + */ +struct lp8758_platform_data { + + int irq; + u32 sub_version; + u32 buck_ctrl[LP8758_BUCK_MAX]; + struct regulator_init_data *buck_data[LP8758_BUCK_MAX]; +}; +#endif /* __LINUX_LP8758_H */ -- 2.26.2