From 3f24bf70a4974122841eb13e3a0621680bd19501 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Feb 2014 14:49:11 +0800 Subject: regulator: rc5t583: Allow missing init_data for diagnostics The regulator core supports this to allow the configuration to be inspected at runtime even if no software management is enabled. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/rc5t583-regulator.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index b58affb33143..22d6fd1281b1 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) { struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); - struct regulator_init_data *reg_data; struct regulator_config config = { }; struct rc5t583_regulator *reg = NULL; struct rc5t583_regulator *regs; @@ -142,12 +141,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { - reg_data = pdata->reg_init_data[id]; - - /* No need to register if there is no regulator data */ - if (!reg_data) - continue; - reg = ®s[id]; ri = &rc5t583_reg_info[id]; reg->reg_info = ri; @@ -169,7 +162,7 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) skip_ext_pwr_config: config.dev = &pdev->dev; - config.init_data = reg_data; + config.init_data = pdata->reg_init_data[id]; config.driver_data = reg; config.regmap = rc5t583->regmap; -- cgit v1.2.3 From c0a3536317357e29c52e32f150114adbce19507b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:19:52 +0530 Subject: regulator: max8997: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/max8997.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 2d618fc9c1af..10108f2941e3 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -924,7 +924,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_find_node_by_name(pmic_np, "regulators"); + regulators_np = of_get_child_by_name(pmic_np, "regulators"); if (!regulators_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; -- cgit v1.2.3 From fc5a6e5b0cf107517910b139e3d3af803fa09952 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:19:59 +0530 Subject: regulator: mc13xxx: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/mc13xxx-regulator-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index da4859282302..4498a3f0733d 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -168,7 +168,7 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) int num; of_node_get(pdev->dev.parent->of_node); - parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return -ENODEV; @@ -188,7 +188,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( int i, parsed = 0; of_node_get(pdev->dev.parent->of_node); - parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return NULL; -- cgit v1.2.3 From d7857c429475677a6a42d0dce7f870d6241edd41 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 17:20:00 +0530 Subject: regulator: pfuze100: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index ab174f20ca11..3cb19aef475d 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -254,7 +254,7 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) if (!np) return 0; - parent = of_find_node_by_name(np, "regulators"); + parent = of_get_child_by_name(np, "regulators"); if (!parent) { dev_err(dev, "regulators node not found\n"); return -EINVAL; -- cgit v1.2.3 From 58c9537791018f1cbe1c2b46128207758dce3745 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Feb 2014 14:33:35 +0530 Subject: regulator: max8998: Add missing of_node_put Add of_node_put to decrement the ref count. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/max8998.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index ae3f0656feb0..ce22d4f3f3eb 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -674,8 +674,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); - if (!rdata) + if (!rdata) { + of_node_put(regulators_np); return -ENOMEM; + } pdata->regulators = rdata; for (i = 0; i < ARRAY_SIZE(regulators); ++i) { @@ -692,6 +694,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, } pdata->num_regulators = rdata - pdata->regulators; + of_node_put(reg_np); + of_node_put(regulators_np); + ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); if (ret) return -EINVAL; -- cgit v1.2.3 From 3e01c75a45740ef4a0ec657d7ca25ad0aa2f50e0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 18 Feb 2014 23:46:14 -0300 Subject: pfuze100-regulator: Fix of_node_get() parameter Since commit d7857c42 (regulator: pfuze100: Use of_get_child_by_name) we get the following probe failure: pfuze100-regulator 1-0008: Full layer: 1, Metal layer: 0 pfuze100-regulator 1-0008: FAB: 0, FIN: 0 pfuze100-regulator 1-0008: regulators node not found pfuze100-regulator: probe of 1-0008 failed with error -22 Now that of_get_child_by_name() is used we should adjust the device_node pointer 'np' to not get the parent node anymore. Suggested-by: Shawn Guo Signed-off-by: Fabio Estevam Acked-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 3cb19aef475d..9bd8b68f3d98 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -250,7 +250,7 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) struct device_node *np, *parent; int ret; - np = of_node_get(dev->parent->of_node); + np = of_node_get(dev->of_node); if (!np) return 0; -- cgit v1.2.3 From 21024dee20ae617ed57594843b08d710f24e72ee Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Feb 2014 16:11:00 +0530 Subject: regulator: max8973: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 892aa1e5b96c..79f57fef0038 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -379,10 +379,8 @@ static int max8973_probe(struct i2c_client *client, } max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); - if (!max) { - dev_err(&client->dev, "Memory allocation for max failed\n"); + if (!max) return -ENOMEM; - } max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config); if (IS_ERR(max->regmap)) { -- cgit v1.2.3 From f0d5c73af6e02ca49a51332360171a3da40dcbf7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 20 Feb 2014 14:23:09 +0530 Subject: regulator: max8997: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/max8997.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 10108f2941e3..f657d8db9c0c 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -937,7 +937,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, pdata->num_regulators, GFP_KERNEL); if (!rdata) { of_node_put(regulators_np); - dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); return -ENOMEM; } -- cgit v1.2.3 From 2ea2583f2f20ba9b68ee6537fcb7e2b829d6928d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 20 Feb 2014 14:23:10 +0530 Subject: regulator: rc5t583: Remove redundant error message kzalloc prints its own OOM message upon failure. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/rc5t583-regulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 22d6fd1281b1..4c414ae109ae 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -134,10 +134,8 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * sizeof(struct rc5t583_regulator), GFP_KERNEL); - if (!regs) { - dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + if (!regs) return -ENOMEM; - } for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { -- cgit v1.2.3 From 6428789e11f056d58ed59c0c0aa7d381d0bf50f8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 20 Feb 2014 13:47:02 -0300 Subject: pfuze100-regulator: Return error on of_node_get() failure If of_node_get() fails, we should return an error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 9bd8b68f3d98..371a55374edc 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -252,7 +252,7 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) np = of_node_get(dev->of_node); if (!np) - return 0; + return -EINVAL; parent = of_get_child_by_name(np, "regulators"); if (!parent) { -- cgit v1.2.3 From bf7f882b1ecef99eedfe36c214458fd457cf7d86 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 25 Feb 2014 16:49:27 +0530 Subject: regulator: mc13xxx: Fix NULL pointer error in non-DT mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a check to avoid NULL pointer dereference error when booted in non-DT mode. While at it also remove the additional of_node_get which is no longer needed for of_get_child_by_name and fix the node pointer. Signed-off-by: Sachin Kamat Reported-by: Philippe Rétornaz Signed-off-by: Mark Brown --- drivers/regulator/mc13xxx-regulator-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 4498a3f0733d..bf75fcabfa3c 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) struct device_node *parent; int num; - of_node_get(pdev->dev.parent->of_node); - parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!pdev->dev.of_node) + return -ENODEV; + + parent = of_get_child_by_name(pdev->dev.of_node, "regulators"); if (!parent) return -ENODEV; @@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct device_node *parent, *child; int i, parsed = 0; - of_node_get(pdev->dev.parent->of_node); - parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!pdev->dev.of_node) + return NULL; + + parent = of_get_child_by_name(pdev->dev.of_node, "regulators"); if (!parent) return NULL; -- cgit v1.2.3 From b431e69a6f2eef526e07819bb8a78d5d2876ff62 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 2 Mar 2014 11:44:35 +0400 Subject: regulator: mc13xxx: Fix probing with DT The nodes of regulators should be retrieved from parent device. Bug was be introduced by commit (regulator: mc13xxx: Fix NULL pointer error in non-DT mode) in conjuction with (mfd: Revert "mfd: Always assign of_node in mfd_add_device()"). Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/regulator/mc13xxx-regulator-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index bf75fcabfa3c..05b971726ffa 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -167,10 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) struct device_node *parent; int num; - if (!pdev->dev.of_node) + if (!pdev->dev.parent->of_node) return -ENODEV; - parent = of_get_child_by_name(pdev->dev.of_node, "regulators"); + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return -ENODEV; @@ -189,10 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct device_node *parent, *child; int i, parsed = 0; - if (!pdev->dev.of_node) + if (!pdev->dev.parent->of_node) return NULL; - parent = of_get_child_by_name(pdev->dev.of_node, "regulators"); + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return NULL; -- cgit v1.2.3 From 3119525203149fc11ce9f48131afdf9795d7a4ea Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:01:48 +0100 Subject: regulator: s2mps11: Don't store registered regulators in state container Regulators registered by devm_regulator_register() do not have to be stored in state container because they are never dereferenced later. The array of regulator_dev can be safely removed from state container. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index cd0b9e35a56d..3647d590b962 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -28,8 +28,6 @@ #define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) struct s2mps11_info { - struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; - int ramp_delay2; int ramp_delay34; int ramp_delay5; @@ -439,6 +437,8 @@ common_reg: config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + struct regulator_dev *regulator; + if (!reg_np) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].reg_node; @@ -447,10 +447,10 @@ common_reg: config.of_node = rdata[i].of_node; } - s2mps11->rdev[i] = devm_regulator_register(&pdev->dev, + regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); - if (IS_ERR(s2mps11->rdev[i])) { - ret = PTR_ERR(s2mps11->rdev[i]); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); dev_err(&pdev->dev, "regulator init failed for %d\n", i); return ret; -- cgit v1.2.3 From 219ef031de434591bb6c85d22701ce8b23c4b1a4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:01:49 +0100 Subject: regulator: s2mps11: Constify regulator_desc array Constify the regulator_desc 'regulators' array. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 3647d590b962..189038aecbf5 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -343,7 +343,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { regulator_desc_ldo2(1), regulator_desc_ldo1(2), regulator_desc_ldo1(3), -- cgit v1.2.3 From 3e80f95bfc5f490bda4785cb672490f7012a40d0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:01:50 +0100 Subject: regulator: s2mps11: Copy supported regulators from initconst Add __initconst to 'regulator_desc' array with supported regulators. During probe choose how many and which regulators will be supported according to device ID. Then copy the 'regulator_desc' array to allocated memory so the regulator core can use it. Additionally allocate array of of_regulator_match() dynamically (based on number of regulators) instead of allocation on the stack. This is needed for supporting different devices in s2mps11 driver and actually prepares the regulator driver for supporting the S2MPS14 device. Code for supporting the S2MPS14 device will add its own array of 'regulator_desc' (also marked as __initconst). This way memory footprint of the driver will be reduced (approximately 'regulators_desc' array for S2MPS11 occupies 5 kB on 32-bit ARM, for S2MPS14 will occupy 3 kB). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi Cc: Yadwinder Singh Brar Reviewed-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 75 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 189038aecbf5..ca66fc56fa58 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -25,9 +25,8 @@ #include #include -#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) - struct s2mps11_info { + unsigned int rdev_num; int ramp_delay2; int ramp_delay34; int ramp_delay5; @@ -343,7 +342,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -static const struct regulator_desc regulators[] = { +static const struct regulator_desc s2mps11_regulators[] __initconst = { regulator_desc_ldo2(1), regulator_desc_ldo1(2), regulator_desc_ldo1(3), @@ -394,21 +393,62 @@ static const struct regulator_desc regulators[] = { regulator_desc_buck10, }; +/* + * Allocates memory under 'regulators' pointer and copies there array + * of regulator_desc for given device. + * + * Returns number of regulators or negative ERRNO on error. + */ +static int __init +s2mps11_pmic_init_regulators_desc(struct platform_device *pdev, + struct regulator_desc **regulators) +{ + const struct regulator_desc *regulators_init; + enum sec_device_type dev_type; + int rdev_num; + + dev_type = platform_get_device_id(pdev)->driver_data; + switch (dev_type) { + case S2MPS11X: + rdev_num = ARRAY_SIZE(s2mps11_regulators); + regulators_init = s2mps11_regulators; + break; + default: + dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); + return -EINVAL; + }; + + *regulators = devm_kzalloc(&pdev->dev, + sizeof(**regulators) * rdev_num, GFP_KERNEL); + if (!*regulators) + return -ENOMEM; + + memcpy(*regulators, regulators_init, sizeof(**regulators) * rdev_num); + + return rdev_num; +} + static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); - struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; + struct sec_platform_data *pdata = iodev->pdata; + struct of_regulator_match *rdata = NULL; struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; - int i, ret; + int i, ret = 0; + struct regulator_desc *regulators = NULL; + int rdev_num; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; + rdev_num = s2mps11_pmic_init_regulators_desc(pdev, ®ulators); + if (rdev_num < 0) + return rdev_num; + if (!iodev->dev->of_node) { if (pdata) { goto common_reg; @@ -419,24 +459,30 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } } - for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) + rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL); + if (!rdata) + return -ENOMEM; + + for (i = 0; i < rdev_num; i++) rdata[i].name = regulators[i].name; reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); if (!reg_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } - of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); + of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num); common_reg: platform_set_drvdata(pdev, s2mps11); + s2mps11->rdev_num = rdev_num; config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; if (!reg_np) { @@ -453,15 +499,18 @@ common_reg: ret = PTR_ERR(regulator); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - return ret; + goto out; } } - return 0; +out: + kfree(rdata); + + return ret; } static const struct platform_device_id s2mps11_pmic_id[] = { - { "s2mps11-pmic", 0}, + { "s2mps11-pmic", S2MPS11X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); -- cgit v1.2.3 From 0f4cc282951a76011db1da6787b3d2acc63238ca Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Mar 2014 16:53:51 +0100 Subject: regulator: s2mps11: Fix section mismatch Remove __initconst from regulator_desc array because this array is used during probe and s2mps11_pmic_probe() is not in __init section. However still select the number of supported regulators according to device ID so the driver will be ready for adding support for S2MPS14 device. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 63 ++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 46 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index ca66fc56fa58..ca876de72eae 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -342,7 +342,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -static const struct regulator_desc s2mps11_regulators[] __initconst = { +static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_ldo2(1), regulator_desc_ldo1(2), regulator_desc_ldo1(3), @@ -393,41 +393,6 @@ static const struct regulator_desc s2mps11_regulators[] __initconst = { regulator_desc_buck10, }; -/* - * Allocates memory under 'regulators' pointer and copies there array - * of regulator_desc for given device. - * - * Returns number of regulators or negative ERRNO on error. - */ -static int __init -s2mps11_pmic_init_regulators_desc(struct platform_device *pdev, - struct regulator_desc **regulators) -{ - const struct regulator_desc *regulators_init; - enum sec_device_type dev_type; - int rdev_num; - - dev_type = platform_get_device_id(pdev)->driver_data; - switch (dev_type) { - case S2MPS11X: - rdev_num = ARRAY_SIZE(s2mps11_regulators); - regulators_init = s2mps11_regulators; - break; - default: - dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); - return -EINVAL; - }; - - *regulators = devm_kzalloc(&pdev->dev, - sizeof(**regulators) * rdev_num, GFP_KERNEL); - if (!*regulators) - return -ENOMEM; - - memcpy(*regulators, regulators_init, sizeof(**regulators) * rdev_num); - - return rdev_num; -} - static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); @@ -437,17 +402,24 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret = 0; - struct regulator_desc *regulators = NULL; - int rdev_num; + const struct regulator_desc *regulators; + enum sec_device_type dev_type; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; - rdev_num = s2mps11_pmic_init_regulators_desc(pdev, ®ulators); - if (rdev_num < 0) - return rdev_num; + dev_type = platform_get_device_id(pdev)->driver_data; + switch (dev_type) { + case S2MPS11X: + s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators); + regulators = s2mps11_regulators; + break; + default: + dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); + return -EINVAL; + }; if (!iodev->dev->of_node) { if (pdata) { @@ -459,11 +431,11 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } } - rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL); + rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL); if (!rdata) return -ENOMEM; - for (i = 0; i < rdev_num; i++) + for (i = 0; i < s2mps11->rdev_num; i++) rdata[i].name = regulators[i].name; reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); @@ -473,16 +445,15 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) goto out; } - of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num); + of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); common_reg: platform_set_drvdata(pdev, s2mps11); - s2mps11->rdev_num = rdev_num; config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - for (i = 0; i < rdev_num; i++) { + for (i = 0; i < s2mps11->rdev_num; i++) { struct regulator_dev *regulator; if (!reg_np) { -- cgit v1.2.3 From f2518480c7b744296a5587990a54e3a284d932b8 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Tue, 4 Mar 2014 17:40:36 +0800 Subject: regulator: pfuze100: add pfuze200 support support pfuze200 chip which remove SW1C and SW4 based on pfuze100. Signed-off-by: Robin Gong Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/pfuze100.txt | 96 +++++++++- drivers/regulator/pfuze100-regulator.c | 196 +++++++++++++++------ include/linux/regulator/pfuze100.h | 14 ++ 3 files changed, 251 insertions(+), 55 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt index fc989b2e8057..34ef5d16d0f1 100644 --- a/Documentation/devicetree/bindings/regulator/pfuze100.txt +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -1,7 +1,7 @@ PFUZE100 family of regulators Required properties: -- compatible: "fsl,pfuze100" +- compatible: "fsl,pfuze100" or "fsl,pfuze200" - reg: I2C slave address Required child node: @@ -10,11 +10,14 @@ Required child node: Documentation/devicetree/bindings/regulator/regulator.txt. The valid names for regulators are: + --PFUZE100 sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 + --PFUZE200 + sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6 Each regulator is defined using the standard binding for regulators. -Example: +Example 1: PFUZE100 pmic: pfuze100@08 { compatible = "fsl,pfuze100"; @@ -113,3 +116,92 @@ Example: }; }; }; + + +Example 2: PFUZE200 + + pmic: pfuze200@08 { + compatible = "fsl,pfuze200"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 371a55374edc..ef330e69336a 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -56,6 +56,8 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 +enum chips {PFUZE100, PFUZE200, PFUZE_NUM}; + struct pfuze_regulator { struct regulator_desc desc; unsigned char stby_reg; @@ -63,6 +65,7 @@ struct pfuze_regulator { }; struct pfuze_chip { + int chip_id; struct regmap *regmap; struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; @@ -77,15 +80,15 @@ static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; -static const struct i2c_device_id pfuze_device_id[] = { - {.name = "pfuze100"}, - {}, +static const struct i2c_device_id pfuze_device_id[PFUZE_NUM] = { + {.name = "pfuze100", .driver_data = PFUZE100}, + {.name = "pfuze200", .driver_data = PFUZE200}, }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); -static const struct of_device_id pfuze_dt_ids[] = { - { .compatible = "fsl,pfuze100" }, - {}, +static const struct of_device_id pfuze_dt_ids[PFUZE_NUM] = { + { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, + { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); @@ -139,14 +142,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }; -#define PFUZE100_FIXED_REG(_name, base, voltage) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = 1, \ .ops = &pfuze100_fixed_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (voltage), \ .enable_reg = (base), \ @@ -154,14 +157,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }, \ } -#define PFUZE100_SW_REG(_name, base, min, max, step) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name,\ .n_voltages = ((max) - (min)) / (step) + 1, \ .ops = &pfuze100_sw_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (min), \ .uV_step = (step), \ @@ -172,14 +175,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x3f, \ } -#define PFUZE100_SWB_REG(_name, base, mask, voltages) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(voltages), \ .ops = &pfuze100_swb_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .volt_table = voltages, \ .vsel_reg = (base), \ @@ -187,14 +190,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }, \ } -#define PFUZE100_VGEN_REG(_name, base, min, max, step) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = ((max) - (min)) / (step) + 1, \ .ops = &pfuze100_ldo_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (min), \ .uV_step = (step), \ @@ -207,25 +210,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x20, \ } +/* PFUZE100 */ static struct pfuze_regulator pfuze100_regulators[] = { - PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), - PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), - PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), - PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), - PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), - PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), - PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), - PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), - PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), - PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), - PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), - PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), - PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), - PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), + PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), + PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + +static struct pfuze_regulator pfuze200_regulators[] = { + PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), + PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; +static struct pfuze_regulator *pfuze_regulators; + #ifdef CONFIG_OF +/* PFUZE100 */ static struct of_regulator_match pfuze100_matches[] = { { .name = "sw1ab", }, { .name = "sw1c", }, @@ -244,6 +267,26 @@ static struct of_regulator_match pfuze100_matches[] = { { .name = "vgen6", }, }; +/* PFUZE200 */ +static struct of_regulator_match pfuze200_matches[] = { + + { .name = "sw1ab", }, + { .name = "sw2", }, + { .name = "sw3a", }, + { .name = "sw3b", }, + { .name = "swbst", }, + { .name = "vsnvs", }, + { .name = "vrefddr", }, + { .name = "vgen1", }, + { .name = "vgen2", }, + { .name = "vgen3", }, + { .name = "vgen4", }, + { .name = "vgen5", }, + { .name = "vgen6", }, +}; + +static struct of_regulator_match *pfuze_matches; + static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) { struct device *dev = chip->dev; @@ -260,8 +303,20 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) return -EINVAL; } - ret = of_regulator_match(dev, parent, pfuze100_matches, - ARRAY_SIZE(pfuze100_matches)); + switch (chip->chip_id) { + case PFUZE200: + pfuze_matches = pfuze200_matches; + ret = of_regulator_match(dev, parent, pfuze200_matches, + ARRAY_SIZE(pfuze200_matches)); + break; + + case PFUZE100: + default: + pfuze_matches = pfuze100_matches; + ret = of_regulator_match(dev, parent, pfuze100_matches, + ARRAY_SIZE(pfuze100_matches)); + break; + } of_node_put(parent); if (ret < 0) { @@ -275,12 +330,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) static inline struct regulator_init_data *match_init_data(int index) { - return pfuze100_matches[index].init_data; + return pfuze_matches[index].init_data; } static inline struct device_node *match_of_node(int index) { - return pfuze100_matches[index].of_node; + return pfuze_matches[index].of_node; } #else static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -308,16 +363,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) if (ret) return ret; - switch (value & 0x0f) { - /* - * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 - * as ID=8 - */ - case 0x8: + if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) { + /* + * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 + * as ID=8 in PFUZE100 + */ dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); - case 0x0: - break; - default: + } else if ((value & 0x0f) != pfuze_chip->chip_id) { + /* device id NOT match with your setting */ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); return -ENODEV; } @@ -353,17 +406,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client, dev_get_platdata(&client->dev); struct regulator_config config = { }; int i, ret; + const struct of_device_id *match; + u32 regulator_num; + u32 sw_check_start, sw_check_end; pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), GFP_KERNEL); if (!pfuze_chip) return -ENOMEM; - i2c_set_clientdata(client, pfuze_chip); - - memcpy(pfuze_chip->regulator_descs, pfuze100_regulators, - sizeof(pfuze_chip->regulator_descs)); + if (client->dev.of_node) { + match = of_match_device(of_match_ptr(pfuze_dt_ids), + &client->dev); + if (!match) { + dev_err(&client->dev, "Error: No device match found\n"); + return -ENODEV; + } + pfuze_chip->chip_id = (int)(long)match->data; + } else if (id) { + pfuze_chip->chip_id = id->driver_data; + } else { + dev_err(&client->dev, "No dts match or id table match found\n"); + return -ENODEV; + } + i2c_set_clientdata(client, pfuze_chip); pfuze_chip->dev = &client->dev; pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); @@ -380,11 +447,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client, return ret; } + /* use the right regulators after identify the right device */ + switch (pfuze_chip->chip_id) { + case PFUZE200: + pfuze_regulators = pfuze200_regulators; + regulator_num = ARRAY_SIZE(pfuze200_regulators); + sw_check_start = PFUZE200_SW2; + sw_check_end = PFUZE200_SW3B; + break; + + case PFUZE100: + default: + pfuze_regulators = pfuze100_regulators; + regulator_num = ARRAY_SIZE(pfuze100_regulators); + sw_check_start = PFUZE100_SW2; + sw_check_end = PFUZE100_SW4; + break; + } + dev_info(&client->dev, "pfuze%s found.\n", + (pfuze_chip->chip_id == PFUZE100) ? "100" : "200"); + + memcpy(pfuze_chip->regulator_descs, pfuze_regulators, + sizeof(pfuze_chip->regulator_descs)); + ret = pfuze_parse_regulators_dt(pfuze_chip); if (ret) return ret; - for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) { + for (i = 0; i < regulator_num; i++) { struct regulator_init_data *init_data; struct regulator_desc *desc; int val; @@ -397,7 +487,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, init_data = match_init_data(i); /* SW2~SW4 high bit check and modify the voltage value table */ - if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) { + if (i >= sw_check_start && i <= sw_check_end) { regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); if (val & 0x40) { desc->min_uV = 800000; @@ -415,7 +505,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, devm_regulator_register(&client->dev, desc, &config); if (IS_ERR(pfuze_chip->regulators[i])) { dev_err(&client->dev, "register regulator%s failed\n", - pfuze100_regulators[i].desc.name); + pfuze_regulators[i].desc.name); return PTR_ERR(pfuze_chip->regulators[i]); } } diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h index 65d550bf3954..364f7a7c43db 100644 --- a/include/linux/regulator/pfuze100.h +++ b/include/linux/regulator/pfuze100.h @@ -35,6 +35,20 @@ #define PFUZE100_VGEN6 14 #define PFUZE100_MAX_REGULATOR 15 +#define PFUZE200_SW1AB 0 +#define PFUZE200_SW2 1 +#define PFUZE200_SW3A 2 +#define PFUZE200_SW3B 3 +#define PFUZE200_SWBST 4 +#define PFUZE200_VSNVS 5 +#define PFUZE200_VREFDDR 6 +#define PFUZE200_VGEN1 7 +#define PFUZE200_VGEN2 8 +#define PFUZE200_VGEN3 9 +#define PFUZE200_VGEN4 10 +#define PFUZE200_VGEN5 11 +#define PFUZE200_VGEN6 12 + struct regulator_init_data; struct pfuze_regulator_platform_data { -- cgit v1.2.3 From e6c4c3378d82c5eeb136ed06b1a23651bcdaf739 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Mar 2014 18:20:14 +0800 Subject: regulator: pfuze100: Add terminate entry for [i2c|of]_device_id tables Also remove PFUZE_NUM to avoid below build warnings: CC [M] drivers/regulator/pfuze100-regulator.o drivers/regulator/pfuze100-regulator.c:86:2: warning: excess elements in array initializer [enabled by default] drivers/regulator/pfuze100-regulator.c:86:2: warning: (near initialization for 'pfuze_device_id') [enabled by default] drivers/regulator/pfuze100-regulator.c:93:2: warning: excess elements in array initializer [enabled by default] drivers/regulator/pfuze100-regulator.c:93:2: warning: (near initialization for 'pfuze_dt_ids') [enabled by default] Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index ef330e69336a..f81c5bffbbf9 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -56,7 +56,7 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 -enum chips {PFUZE100, PFUZE200, PFUZE_NUM}; +enum chips { PFUZE100, PFUZE200 }; struct pfuze_regulator { struct regulator_desc desc; @@ -80,15 +80,17 @@ static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; -static const struct i2c_device_id pfuze_device_id[PFUZE_NUM] = { +static const struct i2c_device_id pfuze_device_id[] = { {.name = "pfuze100", .driver_data = PFUZE100}, {.name = "pfuze200", .driver_data = PFUZE200}, + { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); -static const struct of_device_id pfuze_dt_ids[PFUZE_NUM] = { +static const struct of_device_id pfuze_dt_ids[] = { { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, + { } }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); -- cgit v1.2.3 From 2cee2121db44cfeee206d0854bedd52344eea444 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 18:02:43 +0800 Subject: regulator: pfuze100: Add PFUZE200 support to Kconfig and module description Signed-off-by: Axel Lin Acked-by: Robin Gong Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 6 +++--- drivers/regulator/pfuze100-regulator.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6a7932822e37..a048d626843b 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -399,12 +399,12 @@ config REGULATOR_PCF50633 on PCF50633 config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100 regulator driver" + tristate "Freescale PFUZE100/PFUZE200 regulator driver" depends on I2C select REGMAP_I2C help - Say y here to support the regulators found on the Freescale PFUZE100 - PMIC. + Say y here to support the regulators found on the Freescale + PFUZE100/PFUZE200 PMIC. config REGULATOR_RC5T583 tristate "RICOH RC5T583 Power regulators" diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index f81c5bffbbf9..bcdb5153f30a 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -527,6 +527,6 @@ static struct i2c_driver pfuze_driver = { module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong "); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("i2c:pfuze100-regulator"); -- cgit v1.2.3 From 9654fbe9cda227bb1881f20cc69a7f477a4537f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 10 Mar 2014 09:32:51 +0100 Subject: regulator: max8973: Remove unused field from 'struct max8973_chip' The 'struct regulator_dev *rdev' of 'struct max8973_chip' isn't used anywhere in the driver so it can be removed safely. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 79f57fef0038..dbedf1768db0 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -93,7 +93,6 @@ struct max8973_chip { struct device *dev; struct regulator_desc desc; - struct regulator_dev *rdev; struct regmap *regmap; bool enable_external_control; int dvs_gpio; @@ -472,7 +471,6 @@ static int max8973_probe(struct i2c_client *client, return ret; } - max->rdev = rdev; return 0; } -- cgit v1.2.3 From ad78bba42adcbfedf7a3d53ad1247bc079b4a24c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Mar 2014 15:29:31 +0800 Subject: regulator: max8997: Remove unnecessary **rdev from struct max8997_data Now we are using devm_regulator_register(), so we don't need to allocate *rdev[] array to store return value of devm_regulator_register. Use a *rdev variable is enough for checking return status. Signed-off-by: Axel Lin Acked-by: MyungJoo Ham Signed-off-by: Mark Brown --- drivers/regulator/max8997.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index f657d8db9c0c..90b4c530dee5 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -38,7 +38,6 @@ struct max8997_data { struct device *dev; struct max8997_dev *iodev; int num_regulators; - struct regulator_dev **rdev; int ramp_delay; /* in mV/us */ bool buck1_gpiodvs; @@ -1029,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev) struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct max8997_data *max8997; struct i2c_client *i2c; - int i, ret, size, nr_dvs; + int i, ret, nr_dvs; u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; if (!pdata) { @@ -1051,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev) if (!max8997) return -ENOMEM; - size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!max8997->rdev) - return -ENOMEM; - - rdev = max8997->rdev; max8997->dev = &pdev->dev; max8997->iodev = iodev; max8997->num_regulators = pdata->num_regulators; @@ -1204,12 +1197,12 @@ static int max8997_pmic_probe(struct platform_device *pdev) config.driver_data = max8997; config.of_node = pdata->regulators[i].reg_node; - rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], - &config); - if (IS_ERR(rdev[i])) { + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); + if (IS_ERR(rdev)) { dev_err(max8997->dev, "regulator init failed for %d\n", id); - return PTR_ERR(rdev[i]); + return PTR_ERR(rdev); } } -- cgit v1.2.3 From 8a221df6996f296aba4d4d713a42799bb28fde69 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Mar 2014 15:32:19 +0800 Subject: regulator: max8998: Remove unnecessary **rdev from struct max8998_data Now we are using devm_regulator_register(), so we don't need to allocate *rdev[] array to store return value of devm_regulator_register. Use a *rdev variable is enough for checking return status. Signed-off-by: Axel Lin Acked-by: MyungJoo Ham Signed-off-by: Mark Brown --- drivers/regulator/max8998.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index ce22d4f3f3eb..961091b46557 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -40,7 +40,6 @@ struct max8998_data { struct device *dev; struct max8998_dev *iodev; int num_regulators; - struct regulator_dev **rdev; u8 buck1_vol[4]; /* voltages for selection */ u8 buck2_vol[2]; unsigned int buck1_idx; /* index to last changed voltage */ @@ -746,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev) struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct max8998_data *max8998; struct i2c_client *i2c; - int i, ret, size; + int i, ret; unsigned int v; if (!pdata) { @@ -768,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev) if (!max8998) return -ENOMEM; - size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!max8998->rdev) - return -ENOMEM; - - rdev = max8998->rdev; max8998->dev = &pdev->dev; max8998->iodev = iodev; max8998->num_regulators = pdata->num_regulators; @@ -877,13 +870,12 @@ static int max8998_pmic_probe(struct platform_device *pdev) config.init_data = pdata->regulators[i].initdata; config.driver_data = max8998; - rdev[i] = devm_regulator_register(&pdev->dev, - ®ulators[index], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + rdev = devm_regulator_register(&pdev->dev, ®ulators[index], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(max8998->dev, "regulator %s init failed (%d)\n", regulators[index].name, ret); - rdev[i] = NULL; return ret; } } -- cgit v1.2.3 From b07e2b70b9a1ff9f59af66fd0085c1c52178f440 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:41:41 +0100 Subject: mfd: sec-core: Add maximum RTC register for regmap config Add maximum register to the regmap used by rtc-s5m driver. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 2 ++ include/linux/mfd/samsung/rtc.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 714e2135210e..306b3a282c29 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -141,6 +141,8 @@ static const struct regmap_config s5m8767_regmap_config = { static const struct regmap_config sec_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, + + .max_register = SEC_RTC_REG_MAX, }; #ifdef CONFIG_OF diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index 94b7cd6d8891..4627f59ebd84 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -43,6 +43,8 @@ enum sec_rtc_reg { SEC_RTC_STATUS, SEC_WTSR_SMPL_CNTL, SEC_RTC_UDR_CON, + + SEC_RTC_REG_MAX, }; #define RTC_I2C_ADDR (0x0C >> 1) -- cgit v1.2.3 From 3e5a45f7f16e9f71c0e2ce4f8f5827a8298a8362 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:41:42 +0100 Subject: mfd: sec-core: Select different RTC regmaps for devices This patch prepares for adding support for S2MPS14 RTC driver by selecting different regmaps for S2MPS1X/S5M876X RTC devices. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 306b3a282c29..9623899e6f7c 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -199,7 +199,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); - const struct regmap_config *regmap; + const struct regmap_config *regmap, *regmap_rtc; struct sec_pmic_dev *sec_pmic; int ret; @@ -233,15 +233,25 @@ static int sec_pmic_probe(struct i2c_client *i2c, switch (sec_pmic->device_type) { case S2MPS11X: regmap = &s2mps11_regmap_config; + /* + * The rtc-s5m driver does not support S2MPS11 and there + * is no mfd_cell for S2MPS11 RTC device. + * However we must pass something to devm_regmap_init_i2c() + * so use S5M-like regmap config even though it wouldn't work. + */ + regmap_rtc = &sec_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; + regmap_rtc = &sec_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; + regmap_rtc = &sec_rtc_regmap_config; break; default: regmap = &sec_regmap_config; + regmap_rtc = &sec_rtc_regmap_config; break; } @@ -256,8 +266,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); i2c_set_clientdata(sec_pmic->rtc, sec_pmic); - sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, - &sec_rtc_regmap_config); + sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); if (IS_ERR(sec_pmic->regmap_rtc)) { ret = PTR_ERR(sec_pmic->regmap_rtc); dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", -- cgit v1.2.3 From 677620952a0fd1b1618bed57c1ebd94bf3c710f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:41:43 +0100 Subject: mfd: sec-irq: Use consistent S2MPS11 RTC alarm interrupt indexes The S2MPS11 RTC has two alarms: alarm0 and alarm1 (corresponding interrupts are named similarly). Use consistent names for interrupts to limit possible errors. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-irq.c | 8 ++++---- include/linux/mfd/samsung/irq.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 4de494f51d40..e403c293b437 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -59,13 +59,13 @@ static const struct regmap_irq s2mps11_irqs[] = { .reg_offset = 1, .mask = S2MPS11_IRQ_RTC60S_MASK, }, - [S2MPS11_IRQ_RTCA1] = { + [S2MPS11_IRQ_RTCA0] = { .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA1_MASK, + .mask = S2MPS11_IRQ_RTCA0_MASK, }, - [S2MPS11_IRQ_RTCA2] = { + [S2MPS11_IRQ_RTCA1] = { .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA2_MASK, + .mask = S2MPS11_IRQ_RTCA1_MASK, }, [S2MPS11_IRQ_SMPL] = { .reg_offset = 1, diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h index d43b4f9e7fb2..abe1a6aae3b7 100644 --- a/include/linux/mfd/samsung/irq.h +++ b/include/linux/mfd/samsung/irq.h @@ -24,8 +24,8 @@ enum s2mps11_irq { S2MPS11_IRQ_MRB, S2MPS11_IRQ_RTC60S, + S2MPS11_IRQ_RTCA0, S2MPS11_IRQ_RTCA1, - S2MPS11_IRQ_RTCA2, S2MPS11_IRQ_SMPL, S2MPS11_IRQ_RTC1S, S2MPS11_IRQ_WTSR, @@ -47,7 +47,7 @@ enum s2mps11_irq { #define S2MPS11_IRQ_RTC60S_MASK (1 << 0) #define S2MPS11_IRQ_RTCA1_MASK (1 << 1) -#define S2MPS11_IRQ_RTCA2_MASK (1 << 2) +#define S2MPS11_IRQ_RTCA0_MASK (1 << 2) #define S2MPS11_IRQ_SMPL_MASK (1 << 3) #define S2MPS11_IRQ_RTC1S_MASK (1 << 4) #define S2MPS11_IRQ_WTSR_MASK (1 << 5) -- cgit v1.2.3 From dc6919663f7a02d02cc08d605a1f68d6cefe0042 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Feb 2014 11:41:44 +0100 Subject: mfd: sec: Add support for S2MPS14 Add support for S2MPS14 PMIC device to the MFD sec-core driver. The S2MPS14 is similar to S2MPS11 but it has fewer regulators, two clocks instead of three and a little different registers layout. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 48 ++++++++++-- drivers/mfd/sec-irq.c | 89 ++++++++++++++++++++- include/linux/mfd/samsung/core.h | 1 + include/linux/mfd/samsung/irq.h | 27 +++++++ include/linux/mfd/samsung/rtc.h | 55 +++++++++++-- include/linux/mfd/samsung/s2mps14.h | 152 ++++++++++++++++++++++++++++++++++++ 6 files changed, 360 insertions(+), 12 deletions(-) create mode 100644 include/linux/mfd/samsung/s2mps14.h diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 9623899e6f7c..a4df76c160f8 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,16 @@ static const struct mfd_cell s2mps11_devs[] = { } }; +static const struct mfd_cell s2mps14_devs[] = { + { + .name = "s2mps14-pmic", + }, { + .name = "s2mps14-rtc", + }, { + .name = "s2mps14-clk", + } +}; + #ifdef CONFIG_OF static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", @@ -77,6 +88,9 @@ static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s2mps11-pmic", .data = (void *)S2MPS11X, }, + { .compatible = "samsung,s2mps14-pmic", + .data = (void *)S2MPS14X, + }, {}, }; #endif @@ -120,6 +134,15 @@ static const struct regmap_config s2mps11_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static const struct regmap_config s2mps14_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS14_REG_LDODSCH3, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + static const struct regmap_config s5m8763_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -138,13 +161,20 @@ static const struct regmap_config s5m8767_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config sec_rtc_regmap_config = { +static const struct regmap_config s5m_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = SEC_RTC_REG_MAX, }; +static const struct regmap_config s2mps14_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS_RTC_REG_MAX, +}; + #ifdef CONFIG_OF /* * Only the common platform data elements for s5m8767 are parsed here from the @@ -239,19 +269,23 @@ static int sec_pmic_probe(struct i2c_client *i2c, * However we must pass something to devm_regmap_init_i2c() * so use S5M-like regmap config even though it wouldn't work. */ - regmap_rtc = &sec_rtc_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; + break; + case S2MPS14X: + regmap = &s2mps14_regmap_config; + regmap_rtc = &s2mps14_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; - regmap_rtc = &sec_rtc_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; - regmap_rtc = &sec_rtc_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; default: regmap = &sec_regmap_config; - regmap_rtc = &sec_rtc_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; } @@ -298,6 +332,10 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); break; + case S2MPS14X: + ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs, + ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL); + break; default: /* If this happens the probe function is problem */ BUG(); diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index e403c293b437..64e7913aadc6 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -1,7 +1,7 @@ /* * sec-irq.c * - * Copyright (c) 2011 Samsung Electronics Co., Ltd + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd * http://www.samsung.com * * This program is free software; you can redistribute it and/or modify it @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,76 @@ static const struct regmap_irq s2mps11_irqs[] = { }, }; +static const struct regmap_irq s2mps14_irqs[] = { + [S2MPS14_IRQ_PWRONF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRONF_MASK, + }, + [S2MPS14_IRQ_PWRONR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRONR_MASK, + }, + [S2MPS14_IRQ_JIGONBF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_JIGONBF_MASK, + }, + [S2MPS14_IRQ_JIGONBR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_JIGONBR_MASK, + }, + [S2MPS14_IRQ_ACOKBF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_ACOKBF_MASK, + }, + [S2MPS14_IRQ_ACOKBR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_ACOKBR_MASK, + }, + [S2MPS14_IRQ_PWRON1S] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRON1S_MASK, + }, + [S2MPS14_IRQ_MRB] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_MRB_MASK, + }, + [S2MPS14_IRQ_RTC60S] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTC60S_MASK, + }, + [S2MPS14_IRQ_RTCA1] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTCA1_MASK, + }, + [S2MPS14_IRQ_RTCA0] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTCA0_MASK, + }, + [S2MPS14_IRQ_SMPL] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_SMPL_MASK, + }, + [S2MPS14_IRQ_RTC1S] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTC1S_MASK, + }, + [S2MPS14_IRQ_WTSR] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_WTSR_MASK, + }, + [S2MPS14_IRQ_INT120C] = { + .reg_offset = 2, + .mask = S2MPS11_IRQ_INT120C_MASK, + }, + [S2MPS14_IRQ_INT140C] = { + .reg_offset = 2, + .mask = S2MPS11_IRQ_INT140C_MASK, + }, + [S2MPS14_IRQ_TSD] = { + .reg_offset = 2, + .mask = S2MPS14_IRQ_TSD_MASK, + }, +}; static const struct regmap_irq s5m8767_irqs[] = { [S5M8767_IRQ_PWRR] = { @@ -246,6 +317,16 @@ static const struct regmap_irq_chip s2mps11_irq_chip = { .ack_base = S2MPS11_REG_INT1, }; +static const struct regmap_irq_chip s2mps14_irq_chip = { + .name = "s2mps14", + .irqs = s2mps14_irqs, + .num_irqs = ARRAY_SIZE(s2mps14_irqs), + .num_regs = 3, + .status_base = S2MPS14_REG_INT1, + .mask_base = S2MPS14_REG_INT1M, + .ack_base = S2MPS14_REG_INT1, +}; + static const struct regmap_irq_chip s5m8767_irq_chip = { .name = "s5m8767", .irqs = s5m8767_irqs, @@ -297,6 +378,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) sec_pmic->irq_base, &s2mps11_irq_chip, &sec_pmic->irq_data); break; + case S2MPS14X: + ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + sec_pmic->irq_base, &s2mps14_irq_chip, + &sec_pmic->irq_data); + break; default: dev_err(sec_pmic->dev, "Unknown device type %d\n", sec_pmic->device_type); diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 41c9bde410c5..8e9bbb1083d4 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -19,6 +19,7 @@ enum sec_device_type { S5M8763X, S5M8767X, S2MPS11X, + S2MPS14X, }; /** diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h index abe1a6aae3b7..0065f6f1daf4 100644 --- a/include/linux/mfd/samsung/irq.h +++ b/include/linux/mfd/samsung/irq.h @@ -55,6 +55,33 @@ enum s2mps11_irq { #define S2MPS11_IRQ_INT120C_MASK (1 << 0) #define S2MPS11_IRQ_INT140C_MASK (1 << 1) +enum s2mps14_irq { + S2MPS14_IRQ_PWRONF, + S2MPS14_IRQ_PWRONR, + S2MPS14_IRQ_JIGONBF, + S2MPS14_IRQ_JIGONBR, + S2MPS14_IRQ_ACOKBF, + S2MPS14_IRQ_ACOKBR, + S2MPS14_IRQ_PWRON1S, + S2MPS14_IRQ_MRB, + + S2MPS14_IRQ_RTC60S, + S2MPS14_IRQ_RTCA1, + S2MPS14_IRQ_RTCA0, + S2MPS14_IRQ_SMPL, + S2MPS14_IRQ_RTC1S, + S2MPS14_IRQ_WTSR, + + S2MPS14_IRQ_INT120C, + S2MPS14_IRQ_INT140C, + S2MPS14_IRQ_TSD, + + S2MPS14_IRQ_NR, +}; + +/* Masks for interrupts are the same as in s2mps11 */ +#define S2MPS14_IRQ_TSD_MASK (1 << 2) + enum s5m8767_irq { S5M8767_IRQ_PWRR, S5M8767_IRQ_PWRF, diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index 4627f59ebd84..3e02b768d537 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -1,12 +1,17 @@ -/* rtc.h +/* rtc.h * - * Copyright (c) 2011 Samsung Electronics Co., Ltd + * Copyright (c) 2011-2014 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. + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * */ @@ -47,6 +52,37 @@ enum sec_rtc_reg { SEC_RTC_REG_MAX, }; +enum s2mps_rtc_reg { + S2MPS_RTC_CTRL, + S2MPS_WTSR_SMPL_CNTL, + S2MPS_RTC_UDR_CON, + S2MPS_RSVD, + S2MPS_RTC_SEC, + S2MPS_RTC_MIN, + S2MPS_RTC_HOUR, + S2MPS_RTC_WEEKDAY, + S2MPS_RTC_DATE, + S2MPS_RTC_MONTH, + S2MPS_RTC_YEAR, + S2MPS_ALARM0_SEC, + S2MPS_ALARM0_MIN, + S2MPS_ALARM0_HOUR, + S2MPS_ALARM0_WEEKDAY, + S2MPS_ALARM0_DATE, + S2MPS_ALARM0_MONTH, + S2MPS_ALARM0_YEAR, + S2MPS_ALARM1_SEC, + S2MPS_ALARM1_MIN, + S2MPS_ALARM1_HOUR, + S2MPS_ALARM1_WEEKDAY, + S2MPS_ALARM1_DATE, + S2MPS_ALARM1_MONTH, + S2MPS_ALARM1_YEAR, + S2MPS_OFFSRC, + + S2MPS_RTC_REG_MAX, +}; + #define RTC_I2C_ADDR (0x0C >> 1) #define HOUR_12 (1 << 7) @@ -56,6 +92,9 @@ enum sec_rtc_reg { #define ALARM1_STATUS (1 << 2) #define UPDATE_AD (1 << 0) +#define S2MPS_ALARM0_STATUS (1 << 2) +#define S2MPS_ALARM1_STATUS (1 << 1) + /* RTC Control Register */ #define BCD_EN_SHIFT 0 #define BCD_EN_MASK (1 << BCD_EN_SHIFT) @@ -64,6 +103,10 @@ enum sec_rtc_reg { /* RTC Update Register1 */ #define RTC_UDR_SHIFT 0 #define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define S2MPS_RTC_WUDR_SHIFT 4 +#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT) +#define S2MPS_RTC_RUDR_SHIFT 0 +#define S2MPS_RTC_RUDR_MASK (1 << S2MPS_RTC_RUDR_SHIFT) #define RTC_TCON_SHIFT 1 #define RTC_TCON_MASK (1 << RTC_TCON_SHIFT) #define RTC_TIME_EN_SHIFT 3 diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h new file mode 100644 index 000000000000..ec1e0857ddde --- /dev/null +++ b/include/linux/mfd/samsung/s2mps14.h @@ -0,0 +1,152 @@ +/* + * s2mps14.h + * + * Copyright (c) 2014 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __LINUX_MFD_S2MPS14_H +#define __LINUX_MFD_S2MPS14_H + +/* S2MPS14 registers */ +enum s2mps14_reg { + S2MPS14_REG_ID, + S2MPS14_REG_INT1, + S2MPS14_REG_INT2, + S2MPS14_REG_INT3, + S2MPS14_REG_INT1M, + S2MPS14_REG_INT2M, + S2MPS14_REG_INT3M, + S2MPS14_REG_ST1, + S2MPS14_REG_ST2, + S2MPS14_REG_PWRONSRC, + S2MPS14_REG_OFFSRC, + S2MPS14_REG_BU_CHG, + S2MPS14_REG_RTCCTRL, + S2MPS14_REG_CTRL1, + S2MPS14_REG_CTRL2, + S2MPS14_REG_RSVD1, + S2MPS14_REG_RSVD2, + S2MPS14_REG_RSVD3, + S2MPS14_REG_RSVD4, + S2MPS14_REG_RSVD5, + S2MPS14_REG_RSVD6, + S2MPS14_REG_CTRL3, + S2MPS14_REG_RSVD7, + S2MPS14_REG_RSVD8, + S2MPS14_REG_WRSTBI, + S2MPS14_REG_B1CTRL1, + S2MPS14_REG_B1CTRL2, + S2MPS14_REG_B2CTRL1, + S2MPS14_REG_B2CTRL2, + S2MPS14_REG_B3CTRL1, + S2MPS14_REG_B3CTRL2, + S2MPS14_REG_B4CTRL1, + S2MPS14_REG_B4CTRL2, + S2MPS14_REG_B5CTRL1, + S2MPS14_REG_B5CTRL2, + S2MPS14_REG_L1CTRL, + S2MPS14_REG_L2CTRL, + S2MPS14_REG_L3CTRL, + S2MPS14_REG_L4CTRL, + S2MPS14_REG_L5CTRL, + S2MPS14_REG_L6CTRL, + S2MPS14_REG_L7CTRL, + S2MPS14_REG_L8CTRL, + S2MPS14_REG_L9CTRL, + S2MPS14_REG_L10CTRL, + S2MPS14_REG_L11CTRL, + S2MPS14_REG_L12CTRL, + S2MPS14_REG_L13CTRL, + S2MPS14_REG_L14CTRL, + S2MPS14_REG_L15CTRL, + S2MPS14_REG_L16CTRL, + S2MPS14_REG_L17CTRL, + S2MPS14_REG_L18CTRL, + S2MPS14_REG_L19CTRL, + S2MPS14_REG_L20CTRL, + S2MPS14_REG_L21CTRL, + S2MPS14_REG_L22CTRL, + S2MPS14_REG_L23CTRL, + S2MPS14_REG_L24CTRL, + S2MPS14_REG_L25CTRL, + S2MPS14_REG_LDODSCH1, + S2MPS14_REG_LDODSCH2, + S2MPS14_REG_LDODSCH3, +}; + +/* S2MPS14 regulator ids */ +enum s2mps14_regulators { + S2MPS14_LDO1, + S2MPS14_LDO2, + S2MPS14_LDO3, + S2MPS14_LDO4, + S2MPS14_LDO5, + S2MPS14_LDO6, + S2MPS14_LDO7, + S2MPS14_LDO8, + S2MPS14_LDO9, + S2MPS14_LDO10, + S2MPS14_LDO11, + S2MPS14_LDO12, + S2MPS14_LDO13, + S2MPS14_LDO14, + S2MPS14_LDO15, + S2MPS14_LDO16, + S2MPS14_LDO17, + S2MPS14_LDO18, + S2MPS14_LDO19, + S2MPS14_LDO20, + S2MPS14_LDO21, + S2MPS14_LDO22, + S2MPS14_LDO23, + S2MPS14_LDO24, + S2MPS14_LDO25, + S2MPS14_BUCK1, + S2MPS14_BUCK2, + S2MPS14_BUCK3, + S2MPS14_BUCK4, + S2MPS14_BUCK5, + + S2MPS14_REGULATOR_MAX, +}; + +/* Regulator constraints for BUCKx */ +#define S2MPS14_BUCK1235_MIN_600MV 600000 +#define S2MPS14_BUCK4_MIN_1400MV 1400000 +#define S2MPS14_BUCK1235_STEP_6_25MV 6250 +#define S2MPS14_BUCK4_STEP_12_5MV 12500 +#define S2MPS14_BUCK1235_START_SEL 0x20 +#define S2MPS14_BUCK4_START_SEL 0x40 +/* + * Default ramp delay in uv/us. Datasheet says that ramp delay can be + * controlled however it does not specify which register is used for that. + * Let's assume that default value will be set. + */ +#define S2MPS14_BUCK_RAMP_DELAY 12500 + +/* Regulator constraints for different types of LDOx */ +#define S2MPS14_LDO_MIN_800MV 800000 +#define S2MPS14_LDO_MIN_1800MV 1800000 +#define S2MPS14_LDO_STEP_12_5MV 12500 +#define S2MPS14_LDO_STEP_25MV 25000 + +#define S2MPS14_LDO_VSEL_MASK 0x3F +#define S2MPS14_BUCK_VSEL_MASK 0xFF +#define S2MPS14_ENABLE_MASK (0x03 << S2MPS14_ENABLE_SHIFT) +#define S2MPS14_ENABLE_SHIFT 6 +#define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1) +#define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1) + +#endif /* __LINUX_MFD_S2MPS14_H */ -- cgit v1.2.3 From 65aba1e04916d72b30c028730a1e31860c225412 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 11 Feb 2014 10:12:25 +0100 Subject: mfd: sec-core: Fix possible NULL pointer dereference when i2c_new_dummy error During probe the sec-core driver allocates dummy I2C device for RTC with i2c_new_dummy() but return value is not checked. In case of error (i2c_new_device(): memory allocation failure or I2C address cannot be used) this function returns NULL which is later used by devm_regmap_init_i2c() or i2c_unregister_device(). If i2c_new_dummy() fails for RTC device, fail also the probe for main MFD driver. Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index a4df76c160f8..d163c66edebb 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -298,6 +298,10 @@ static int sec_pmic_probe(struct i2c_client *i2c, } sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + if (!sec_pmic->rtc) { + dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); + return -ENODEV; + } i2c_set_clientdata(sec_pmic->rtc, sec_pmic); sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); -- cgit v1.2.3 From 8f695de515b9e08e30c5b7fae48c0672c8361c51 Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Thu, 13 Mar 2014 11:14:07 +0900 Subject: mfd: sec-core: Silence compiler warning When used 64bit compiler GCC warns as drivers/mfd/sec-core.c:199:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] Signed-off-by: Pankaj Dubey Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 6 +++--- include/linux/mfd/samsung/core.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index d163c66edebb..3fc3ebdd7b8a 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -212,17 +212,17 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( } #endif -static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, +static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, const struct i2c_device_id *id) { #ifdef CONFIG_OF if (i2c->dev.of_node) { const struct of_device_id *match; match = of_match_node(sec_dt_match, i2c->dev.of_node); - return (int)match->data; + return (unsigned long)match->data; } #endif - return (int)id->driver_data; + return id->driver_data; } static int sec_pmic_probe(struct i2c_client *i2c, diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 8e9bbb1083d4..5073d81660e7 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -51,7 +51,7 @@ struct sec_pmic_dev { struct regmap_irq_chip_data *irq_data; int ono; - int type; + unsigned long type; bool wakeup; bool wtsr_smpl; }; -- cgit v1.2.3 From ce24991e1e4d7bee05bcc0e156b0b1c2ef791dd3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Mar 2014 17:21:57 +0530 Subject: mfd: Add support for S2MPA01 device Add the necessary entries required for S2MPA01 multi-function device. While at it also convert whitespaces to tabs in core.h. Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 49 ++++++++- include/linux/mfd/samsung/core.h | 16 ++- include/linux/mfd/samsung/irq.h | 50 ++++++++++ include/linux/mfd/samsung/s2mpa01.h | 192 ++++++++++++++++++++++++++++++++++++ 4 files changed, 297 insertions(+), 10 deletions(-) create mode 100644 include/linux/mfd/samsung/s2mpa01.h diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 3fc3ebdd7b8a..281a82747275 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -80,21 +81,43 @@ static const struct mfd_cell s2mps14_devs[] = { } }; +static const struct mfd_cell s2mpa01_devs[] = { + { + .name = "s2mpa01-pmic", + }, +}; + #ifdef CONFIG_OF static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, - }, - { .compatible = "samsung,s2mps11-pmic", + }, { + .compatible = "samsung,s2mps11-pmic", .data = (void *)S2MPS11X, - }, - { .compatible = "samsung,s2mps14-pmic", + }, { + .compatible = "samsung,s2mps14-pmic", .data = (void *)S2MPS14X, + }, { + .compatible = "samsung,s2mpa01-pmic", + .data = (void *)S2MPA01, + }, { + /* Sentinel */ }, - {}, }; #endif +static bool s2mpa01_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPA01_REG_INT1M: + case S2MPA01_REG_INT2M: + case S2MPA01_REG_INT3M: + return false; + default: + return true; + } +} + static bool s2mps11_volatile(struct device *dev, unsigned int reg) { switch (reg) { @@ -125,6 +148,15 @@ static const struct regmap_config sec_regmap_config = { .val_bits = 8, }; +static const struct regmap_config s2mpa01_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPA01_REG_LDO_OVCB4, + .volatile_reg = s2mpa01_volatile, + .cache_type = REGCACHE_FLAT, +}; + static const struct regmap_config s2mps11_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -261,6 +293,9 @@ static int sec_pmic_probe(struct i2c_client *i2c, } switch (sec_pmic->device_type) { + case S2MPA01: + regmap = &s2mpa01_regmap_config; + break; case S2MPS11X: regmap = &s2mps11_regmap_config; /* @@ -332,6 +367,10 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); break; + case S2MPA01: + ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs, + ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL); + break; case S2MPS11X: ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 5073d81660e7..900bc9e1888b 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -18,6 +18,7 @@ enum sec_device_type { S5M8751X, S5M8763X, S5M8767X, + S2MPA01, S2MPS11X, S2MPS14X, }; @@ -93,7 +94,7 @@ struct sec_platform_data { int buck3_default_idx; int buck4_default_idx; - int buck_ramp_delay; + int buck_ramp_delay; int buck2_ramp_delay; int buck34_ramp_delay; @@ -101,10 +102,15 @@ struct sec_platform_data { int buck16_ramp_delay; int buck7810_ramp_delay; int buck9_ramp_delay; - - bool buck2_ramp_enable; - bool buck3_ramp_enable; - bool buck4_ramp_enable; + int buck24_ramp_delay; + int buck3_ramp_delay; + int buck7_ramp_delay; + int buck8910_ramp_delay; + + bool buck1_ramp_enable; + bool buck2_ramp_enable; + bool buck3_ramp_enable; + bool buck4_ramp_enable; bool buck6_ramp_enable; int buck2_init; diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h index 0065f6f1daf4..1224f447356b 100644 --- a/include/linux/mfd/samsung/irq.h +++ b/include/linux/mfd/samsung/irq.h @@ -13,6 +13,56 @@ #ifndef __LINUX_MFD_SEC_IRQ_H #define __LINUX_MFD_SEC_IRQ_H +enum s2mpa01_irq { + S2MPA01_IRQ_PWRONF, + S2MPA01_IRQ_PWRONR, + S2MPA01_IRQ_JIGONBF, + S2MPA01_IRQ_JIGONBR, + S2MPA01_IRQ_ACOKBF, + S2MPA01_IRQ_ACOKBR, + S2MPA01_IRQ_PWRON1S, + S2MPA01_IRQ_MRB, + + S2MPA01_IRQ_RTC60S, + S2MPA01_IRQ_RTCA1, + S2MPA01_IRQ_RTCA0, + S2MPA01_IRQ_SMPL, + S2MPA01_IRQ_RTC1S, + S2MPA01_IRQ_WTSR, + + S2MPA01_IRQ_INT120C, + S2MPA01_IRQ_INT140C, + S2MPA01_IRQ_LDO3_TSD, + S2MPA01_IRQ_B16_TSD, + S2MPA01_IRQ_B24_TSD, + S2MPA01_IRQ_B35_TSD, + + S2MPA01_IRQ_NR, +}; + +#define S2MPA01_IRQ_PWRONF_MASK (1 << 0) +#define S2MPA01_IRQ_PWRONR_MASK (1 << 1) +#define S2MPA01_IRQ_JIGONBF_MASK (1 << 2) +#define S2MPA01_IRQ_JIGONBR_MASK (1 << 3) +#define S2MPA01_IRQ_ACOKBF_MASK (1 << 4) +#define S2MPA01_IRQ_ACOKBR_MASK (1 << 5) +#define S2MPA01_IRQ_PWRON1S_MASK (1 << 6) +#define S2MPA01_IRQ_MRB_MASK (1 << 7) + +#define S2MPA01_IRQ_RTC60S_MASK (1 << 0) +#define S2MPA01_IRQ_RTCA1_MASK (1 << 1) +#define S2MPA01_IRQ_RTCA0_MASK (1 << 2) +#define S2MPA01_IRQ_SMPL_MASK (1 << 3) +#define S2MPA01_IRQ_RTC1S_MASK (1 << 4) +#define S2MPA01_IRQ_WTSR_MASK (1 << 5) + +#define S2MPA01_IRQ_INT120C_MASK (1 << 0) +#define S2MPA01_IRQ_INT140C_MASK (1 << 1) +#define S2MPA01_IRQ_LDO3_TSD_MASK (1 << 2) +#define S2MPA01_IRQ_B16_TSD_MASK (1 << 3) +#define S2MPA01_IRQ_B24_TSD_MASK (1 << 4) +#define S2MPA01_IRQ_B35_TSD_MASK (1 << 5) + enum s2mps11_irq { S2MPS11_IRQ_PWRONF, S2MPS11_IRQ_PWRONR, diff --git a/include/linux/mfd/samsung/s2mpa01.h b/include/linux/mfd/samsung/s2mpa01.h new file mode 100644 index 000000000000..fbc63bc0d6a2 --- /dev/null +++ b/include/linux/mfd/samsung/s2mpa01.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2013 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_S2MPA01_H +#define __LINUX_MFD_S2MPA01_H + +/* S2MPA01 registers */ +enum s2mpa01_reg { + S2MPA01_REG_ID, + S2MPA01_REG_INT1, + S2MPA01_REG_INT2, + S2MPA01_REG_INT3, + S2MPA01_REG_INT1M, + S2MPA01_REG_INT2M, + S2MPA01_REG_INT3M, + S2MPA01_REG_ST1, + S2MPA01_REG_ST2, + S2MPA01_REG_PWRONSRC, + S2MPA01_REG_OFFSRC, + S2MPA01_REG_RTC_BUF, + S2MPA01_REG_CTRL1, + S2MPA01_REG_ETC_TEST, + S2MPA01_REG_RSVD1, + S2MPA01_REG_BU_CHG, + S2MPA01_REG_RAMP1, + S2MPA01_REG_RAMP2, + S2MPA01_REG_LDO_DSCH1, + S2MPA01_REG_LDO_DSCH2, + S2MPA01_REG_LDO_DSCH3, + S2MPA01_REG_LDO_DSCH4, + S2MPA01_REG_OTP_ADRL, + S2MPA01_REG_OTP_ADRH, + S2MPA01_REG_OTP_DATA, + S2MPA01_REG_MON1SEL, + S2MPA01_REG_MON2SEL, + S2MPA01_REG_LEE, + S2MPA01_REG_RSVD2, + S2MPA01_REG_RSVD3, + S2MPA01_REG_RSVD4, + S2MPA01_REG_RSVD5, + S2MPA01_REG_RSVD6, + S2MPA01_REG_TOP_RSVD, + S2MPA01_REG_DVS_SEL, + S2MPA01_REG_DVS_PTR, + S2MPA01_REG_DVS_DATA, + S2MPA01_REG_RSVD_NO, + S2MPA01_REG_UVLO, + S2MPA01_REG_LEE_NO, + S2MPA01_REG_B1CTRL1, + S2MPA01_REG_B1CTRL2, + S2MPA01_REG_B2CTRL1, + S2MPA01_REG_B2CTRL2, + S2MPA01_REG_B3CTRL1, + S2MPA01_REG_B3CTRL2, + S2MPA01_REG_B4CTRL1, + S2MPA01_REG_B4CTRL2, + S2MPA01_REG_B5CTRL1, + S2MPA01_REG_B5CTRL2, + S2MPA01_REG_B5CTRL3, + S2MPA01_REG_B5CTRL4, + S2MPA01_REG_B5CTRL5, + S2MPA01_REG_B5CTRL6, + S2MPA01_REG_B6CTRL1, + S2MPA01_REG_B6CTRL2, + S2MPA01_REG_B7CTRL1, + S2MPA01_REG_B7CTRL2, + S2MPA01_REG_B8CTRL1, + S2MPA01_REG_B8CTRL2, + S2MPA01_REG_B9CTRL1, + S2MPA01_REG_B9CTRL2, + S2MPA01_REG_B10CTRL1, + S2MPA01_REG_B10CTRL2, + S2MPA01_REG_L1CTRL, + S2MPA01_REG_L2CTRL, + S2MPA01_REG_L3CTRL, + S2MPA01_REG_L4CTRL, + S2MPA01_REG_L5CTRL, + S2MPA01_REG_L6CTRL, + S2MPA01_REG_L7CTRL, + S2MPA01_REG_L8CTRL, + S2MPA01_REG_L9CTRL, + S2MPA01_REG_L10CTRL, + S2MPA01_REG_L11CTRL, + S2MPA01_REG_L12CTRL, + S2MPA01_REG_L13CTRL, + S2MPA01_REG_L14CTRL, + S2MPA01_REG_L15CTRL, + S2MPA01_REG_L16CTRL, + S2MPA01_REG_L17CTRL, + S2MPA01_REG_L18CTRL, + S2MPA01_REG_L19CTRL, + S2MPA01_REG_L20CTRL, + S2MPA01_REG_L21CTRL, + S2MPA01_REG_L22CTRL, + S2MPA01_REG_L23CTRL, + S2MPA01_REG_L24CTRL, + S2MPA01_REG_L25CTRL, + S2MPA01_REG_L26CTRL, + + S2MPA01_REG_LDO_OVCB1, + S2MPA01_REG_LDO_OVCB2, + S2MPA01_REG_LDO_OVCB3, + S2MPA01_REG_LDO_OVCB4, + +}; + +/* S2MPA01 regulator ids */ +enum s2mpa01_regulators { + S2MPA01_LDO1, + S2MPA01_LDO2, + S2MPA01_LDO3, + S2MPA01_LDO4, + S2MPA01_LDO5, + S2MPA01_LDO6, + S2MPA01_LDO7, + S2MPA01_LDO8, + S2MPA01_LDO9, + S2MPA01_LDO10, + S2MPA01_LDO11, + S2MPA01_LDO12, + S2MPA01_LDO13, + S2MPA01_LDO14, + S2MPA01_LDO15, + S2MPA01_LDO16, + S2MPA01_LDO17, + S2MPA01_LDO18, + S2MPA01_LDO19, + S2MPA01_LDO20, + S2MPA01_LDO21, + S2MPA01_LDO22, + S2MPA01_LDO23, + S2MPA01_LDO24, + S2MPA01_LDO25, + S2MPA01_LDO26, + + S2MPA01_BUCK1, + S2MPA01_BUCK2, + S2MPA01_BUCK3, + S2MPA01_BUCK4, + S2MPA01_BUCK5, + S2MPA01_BUCK6, + S2MPA01_BUCK7, + S2MPA01_BUCK8, + S2MPA01_BUCK9, + S2MPA01_BUCK10, + + S2MPA01_REGULATOR_MAX, +}; + +#define S2MPA01_BUCK_MIN1 600000 +#define S2MPA01_BUCK_MIN2 800000 +#define S2MPA01_BUCK_MIN3 1000000 +#define S2MPA01_BUCK_MIN4 1500000 +#define S2MPA01_LDO_MIN 800000 + +#define S2MPA01_BUCK_STEP1 6250 +#define S2MPA01_BUCK_STEP2 12500 + +#define S2MPA01_LDO_STEP1 50000 +#define S2MPA01_LDO_STEP2 25000 + +#define S2MPA01_LDO_VSEL_MASK 0x3F +#define S2MPA01_BUCK_VSEL_MASK 0xFF +#define S2MPA01_ENABLE_MASK (0x03 << S2MPA01_ENABLE_SHIFT) +#define S2MPA01_ENABLE_SHIFT 0x06 +#define S2MPA01_LDO_N_VOLTAGES (S2MPA01_LDO_VSEL_MASK + 1) +#define S2MPA01_BUCK_N_VOLTAGES (S2MPA01_BUCK_VSEL_MASK + 1) + +#define S2MPA01_RAMP_DELAY 12500 /* uV/us */ + +#define S2MPA01_BUCK16_RAMP_SHIFT 4 +#define S2MPA01_BUCK24_RAMP_SHIFT 6 +#define S2MPA01_BUCK3_RAMP_SHIFT 4 +#define S2MPA01_BUCK5_RAMP_SHIFT 6 +#define S2MPA01_BUCK7_RAMP_SHIFT 2 +#define S2MPA01_BUCK8910_RAMP_SHIFT 0 + +#define S2MPA01_BUCK1_RAMP_EN_SHIFT 3 +#define S2MPA01_BUCK2_RAMP_EN_SHIFT 2 +#define S2MPA01_BUCK3_RAMP_EN_SHIFT 1 +#define S2MPA01_BUCK4_RAMP_EN_SHIFT 0 +#define S2MPA01_PMIC_EN_SHIFT 6 + +#endif /*__LINUX_MFD_S2MPA01_H */ -- cgit v1.2.3 From f18792714608a670c2762d22f695d77d02fc965e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Mar 2014 17:21:58 +0530 Subject: regulator: Add support for S2MPA01 regulator Add support for S2MPA01 voltage and current regulator. Signed-off-by: Sachin Kamat Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 1 + drivers/regulator/s2mpa01.c | 481 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+) create mode 100644 drivers/regulator/s2mpa01.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6a7932822e37..8f8e6710bb45 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -416,6 +416,13 @@ config REGULATOR_RC5T583 through regulator interface. The device supports multiple DCDC/LDO outputs which can be controlled by i2c communication. +config REGULATOR_S2MPA01 + tristate "Samsung S2MPA01 voltage regulator" + depends on MFD_SEC_CORE + help + This driver controls Samsung S2MPA01 voltage output regulator + via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs. + config REGULATOR_S2MPS11 tristate "Samsung S2MPS11 voltage regulator" depends on MFD_SEC_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 979f9ddcf259..b3ece84289cf 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-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_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c new file mode 100644 index 000000000000..808b3aa7a42c --- /dev/null +++ b/drivers/regulator/s2mpa01.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators) + +struct s2mpa01_info { + int ramp_delay24; + int ramp_delay3; + int ramp_delay5; + int ramp_delay16; + int ramp_delay7; + int ramp_delay8910; +}; + +static int get_ramp_delay(int ramp_delay) +{ + unsigned char cnt = 0; + + ramp_delay /= 6250; + + while (true) { + ramp_delay = ramp_delay >> 1; + if (ramp_delay == 0) + break; + cnt++; + } + + if (cnt > 3) + cnt = 3; + + return cnt; +} + +static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); + unsigned int ramp_delay = 0; + int old_volt, new_volt; + + switch (rdev->desc->id) { + case S2MPA01_BUCK2: + case S2MPA01_BUCK4: + ramp_delay = s2mpa01->ramp_delay24; + break; + case S2MPA01_BUCK3: + ramp_delay = s2mpa01->ramp_delay3; + break; + case S2MPA01_BUCK5: + ramp_delay = s2mpa01->ramp_delay5; + break; + case S2MPA01_BUCK1: + case S2MPA01_BUCK6: + ramp_delay = s2mpa01->ramp_delay16; + break; + case S2MPA01_BUCK7: + ramp_delay = s2mpa01->ramp_delay7; + break; + case S2MPA01_BUCK8: + case S2MPA01_BUCK9: + case S2MPA01_BUCK10: + ramp_delay = s2mpa01->ramp_delay8910; + break; + } + + if (ramp_delay == 0) + ramp_delay = rdev->desc->ramp_delay; + + old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector); + new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector); + + return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); +} + +static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); + unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2; + unsigned int ramp_enable = 1, enable_shift = 0; + int ret; + + switch (rdev->desc->id) { + case S2MPA01_BUCK1: + enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay16) + s2mpa01->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay16; + + ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK2: + enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay24) + s2mpa01->ramp_delay24 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay24; + + ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK3: + enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + s2mpa01->ramp_delay3 = ramp_delay; + ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK4: + enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay24) + s2mpa01->ramp_delay24 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay24; + + ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK5: + s2mpa01->ramp_delay5 = ramp_delay; + ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT; + break; + case S2MPA01_BUCK6: + if (ramp_delay > s2mpa01->ramp_delay16) + s2mpa01->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay16; + + ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; + break; + case S2MPA01_BUCK7: + s2mpa01->ramp_delay7 = ramp_delay; + ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT; + break; + case S2MPA01_BUCK8: + case S2MPA01_BUCK9: + case S2MPA01_BUCK10: + if (ramp_delay > s2mpa01->ramp_delay8910) + s2mpa01->ramp_delay8910 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay8910; + + ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT; + break; + default: + return 0; + } + + if (!ramp_enable) + goto ramp_disable; + + if (enable_shift) { + ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1, + 1 << enable_shift, 1 << enable_shift); + if (ret) { + dev_err(&rdev->dev, "failed to enable ramp rate\n"); + return ret; + } + } + + ramp_val = get_ramp_delay(ramp_delay); + + return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift, + ramp_val << ramp_shift); + +ramp_disable: + return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1, + 1 << enable_shift, 0); +} + +static struct regulator_ops s2mpa01_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops s2mpa01_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = s2mpa01_regulator_set_voltage_time_sel, + .set_ramp_delay = s2mpa01_set_ramp_delay, +}; + +#define regulator_desc_ldo1(num) { \ + .name = "LDO"#num, \ + .id = S2MPA01_LDO##num, \ + .ops = &s2mpa01_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_LDO_MIN, \ + .uV_step = S2MPA01_LDO_STEP1, \ + .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} +#define regulator_desc_ldo2(num) { \ + .name = "LDO"#num, \ + .id = S2MPA01_LDO##num, \ + .ops = &s2mpa01_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_LDO_MIN, \ + .uV_step = S2MPA01_LDO_STEP2, \ + .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck1_4(num) { \ + .name = "BUCK"#num, \ + .id = S2MPA01_BUCK##num, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN1, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck5 { \ + .name = "BUCK5", \ + .id = S2MPA01_BUCK5, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN2, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B5CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B5CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck6_7(num) { \ + .name = "BUCK"#num, \ + .id = S2MPA01_BUCK##num, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN1, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B6CTRL1 + (num - 6) * 2, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck8 { \ + .name = "BUCK8", \ + .id = S2MPA01_BUCK8, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN2, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B8CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B8CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck9 { \ + .name = "BUCK9", \ + .id = S2MPA01_BUCK9, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN4, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B9CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B9CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck10 { \ + .name = "BUCK10", \ + .id = S2MPA01_BUCK10, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN3, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B10CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B10CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo2(1), + regulator_desc_ldo1(2), + regulator_desc_ldo1(3), + regulator_desc_ldo1(4), + regulator_desc_ldo1(5), + regulator_desc_ldo2(6), + regulator_desc_ldo1(7), + regulator_desc_ldo1(8), + regulator_desc_ldo1(9), + regulator_desc_ldo1(10), + regulator_desc_ldo2(11), + regulator_desc_ldo1(12), + regulator_desc_ldo1(13), + regulator_desc_ldo1(14), + regulator_desc_ldo1(15), + regulator_desc_ldo1(16), + regulator_desc_ldo1(17), + regulator_desc_ldo1(18), + regulator_desc_ldo1(19), + regulator_desc_ldo1(20), + regulator_desc_ldo1(21), + regulator_desc_ldo2(22), + regulator_desc_ldo2(23), + regulator_desc_ldo1(24), + regulator_desc_ldo1(25), + regulator_desc_ldo1(26), + regulator_desc_buck1_4(1), + regulator_desc_buck1_4(2), + regulator_desc_buck1_4(3), + regulator_desc_buck1_4(4), + regulator_desc_buck5, + regulator_desc_buck6_7(6), + regulator_desc_buck6_7(7), + regulator_desc_buck8, + regulator_desc_buck9, + regulator_desc_buck10, +}; + +static int s2mpa01_pmic_probe(struct platform_device *pdev) +{ + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); + struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX]; + struct device_node *reg_np = NULL; + struct regulator_config config = { }; + struct s2mpa01_info *s2mpa01; + int i; + + s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL); + if (!s2mpa01) + return -ENOMEM; + + for (i = 0; i < S2MPA01_REGULATOR_CNT; i++) + rdata[i].name = regulators[i].name; + + if (iodev->dev->of_node) { + reg_np = of_get_child_by_name(iodev->dev->of_node, + "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, + "could not find regulators sub-node\n"); + return -EINVAL; + } + + of_regulator_match(&pdev->dev, reg_np, rdata, + S2MPA01_REGULATOR_MAX); + of_node_put(reg_np); + } + + platform_set_drvdata(pdev, s2mpa01); + + config.dev = &pdev->dev; + config.regmap = iodev->regmap_pmic; + config.driver_data = s2mpa01; + + for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) { + struct regulator_dev *rdev; + if (pdata) + config.init_data = pdata->regulators[i].initdata; + else + config.init_data = rdata[i].init_data; + + if (reg_np) + config.of_node = rdata[i].of_node; + + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "regulator init failed for %d\n", + i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id s2mpa01_pmic_id[] = { + { "s2mpa01-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id); + +static struct platform_driver s2mpa01_pmic_driver = { + .driver = { + .name = "s2mpa01-pmic", + .owner = THIS_MODULE, + }, + .probe = s2mpa01_pmic_probe, + .id_table = s2mpa01_pmic_id, +}; + +module_platform_driver(s2mpa01_pmic_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim "); +MODULE_AUTHOR("Sachin Kamat "); +MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ba3e31f87e8b736adf01f1dc09cd5618966ee193 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Mar 2014 17:21:59 +0530 Subject: Documentation: mfd: Add binding document for S2MPA01 Added initial binding documentation for S2MPA01 MFD. Signed-off-by: Sachin Kamat Acked-by: Mark Brown Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/s2mpa01.txt | 90 +++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/s2mpa01.txt diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt new file mode 100644 index 000000000000..c13d3d8c3947 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/s2mpa01.txt @@ -0,0 +1,90 @@ + +* Samsung S2MPA01 Voltage and Current Regulator + +The Samsung S2MPA01 is a multi-function device which includes high +efficiency buck converters including Dual-Phase buck converter, various LDOs, +and an RTC. It is interfaced to the host controller using an I2C interface. +Each sub-block is addressed by the host system using different I2C slave +addresses. + +Required properties: +- compatible: Should be "samsung,s2mpa01-pmic". +- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66. + +Optional properties: +- interrupt-parent: Specifies the phandle of the interrupt controller to which + the interrupts from s2mpa01 are delivered to. +- interrupts: An interrupt specifier for the sole interrupt generated by the + device. + +Optional nodes: +- regulators: The regulators of s2mpa01 that have to be instantiated should be + included in a sub-node named 'regulators'. Regulator nodes and constraints + included in this sub-node use the standard regulator bindings which are + documented elsewhere. + +Properties for BUCK regulator nodes: +- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500 + (default), 25000, or 50000. May be 0 for disabling the ramp delay on + BUCK{1,2,3,4}. + + In the absence of the regulator-ramp-delay property, the default ramp + delay will be used. + + NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set + for a particular group of BUCKs. So provide same regulator-ramp-delay=. + + The following BUCKs share ramp settings: + * 1 and 6 + * 2 and 4 + * 8, 9, and 10 + +The following are the names of the regulators that the s2mpa01 PMIC block +supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of s2mpa01. + + - LDOn + - valid values for n are 1 to 26 + - Example: LDO1, LD02, LDO26 + - BUCKn + - valid values for n are 1 to 10. + - Example: BUCK1, BUCK2, BUCK9 + +Example: + + s2mpa01_pmic@66 { + compatible = "samsung,s2mpa01-pmic"; + reg = <0x66>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ALIVE"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDDQ_MMC2"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <50000>; + }; + }; + }; -- cgit v1.2.3 From 15f77300c9eedb095c8f4097628af51e8e14de30 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 7 Mar 2014 11:10:50 +0100 Subject: regulator: s2mps11: Add support for S2MPS14 regulators Add support for S2MPS14 PMIC regulators to s2mps11 driver. The S2MPS14 has fewer BUCK-s and LDO-s than S2MPS11. It also does not support controlling the BUCK ramp delay. Signed-off-by: Krzysztof Kozlowski Cc: Mark Brown Cc: Liam Girdwood Reviewed-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 +- drivers/regulator/s2mps11.c | 252 +++++++++++++++++++++++++++++++++----------- 2 files changed, 196 insertions(+), 65 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8f8e6710bb45..69e6bf755e00 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -424,12 +424,13 @@ config REGULATOR_S2MPA01 via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs. config REGULATOR_S2MPS11 - tristate "Samsung S2MPS11 voltage regulator" + tristate "Samsung S2MPS11/S2MPS14 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. + This driver supports a Samsung S2MPS11/S2MPS14 voltage output + regulator via I2C bus. The chip 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" diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index ca876de72eae..65697b1a26c0 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1,13 +1,18 @@ /* * s2mps11.c * - * Copyright (c) 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2012-2014 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. + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * */ @@ -24,6 +29,7 @@ #include #include #include +#include struct s2mps11_info { unsigned int rdev_num; @@ -233,7 +239,7 @@ static struct regulator_ops s2mps11_buck_ops = { .set_ramp_delay = s2mps11_set_ramp_delay, }; -#define regulator_desc_ldo1(num) { \ +#define regulator_desc_s2mps11_ldo1(num) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ .ops = &s2mps11_ldo_ops, \ @@ -247,7 +253,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \ .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_ldo2(num) { \ +#define regulator_desc_s2mps11_ldo2(num) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ .ops = &s2mps11_ldo_ops, \ @@ -262,7 +268,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck1_4(num) { \ +#define regulator_desc_s2mps11_buck1_4(num) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -278,7 +284,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck5 { \ +#define regulator_desc_s2mps11_buck5 { \ .name = "BUCK5", \ .id = S2MPS11_BUCK5, \ .ops = &s2mps11_buck_ops, \ @@ -294,7 +300,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck6_8(num) { \ +#define regulator_desc_s2mps11_buck6_8(num) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -310,7 +316,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck9 { \ +#define regulator_desc_s2mps11_buck9 { \ .name = "BUCK9", \ .id = S2MPS11_BUCK9, \ .ops = &s2mps11_buck_ops, \ @@ -326,7 +332,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck10 { \ +#define regulator_desc_s2mps11_buck10 { \ .name = "BUCK10", \ .id = S2MPS11_BUCK10, \ .ops = &s2mps11_buck_ops, \ @@ -343,54 +349,173 @@ static struct regulator_ops s2mps11_buck_ops = { } static const struct regulator_desc s2mps11_regulators[] = { - regulator_desc_ldo2(1), - regulator_desc_ldo1(2), - regulator_desc_ldo1(3), - regulator_desc_ldo1(4), - regulator_desc_ldo1(5), - regulator_desc_ldo2(6), - regulator_desc_ldo1(7), - regulator_desc_ldo1(8), - regulator_desc_ldo1(9), - regulator_desc_ldo1(10), - regulator_desc_ldo2(11), - regulator_desc_ldo1(12), - regulator_desc_ldo1(13), - regulator_desc_ldo1(14), - regulator_desc_ldo1(15), - regulator_desc_ldo1(16), - regulator_desc_ldo1(17), - regulator_desc_ldo1(18), - regulator_desc_ldo1(19), - regulator_desc_ldo1(20), - regulator_desc_ldo1(21), - regulator_desc_ldo2(22), - regulator_desc_ldo2(23), - regulator_desc_ldo1(24), - regulator_desc_ldo1(25), - regulator_desc_ldo1(26), - regulator_desc_ldo2(27), - regulator_desc_ldo1(28), - regulator_desc_ldo1(29), - regulator_desc_ldo1(30), - regulator_desc_ldo1(31), - regulator_desc_ldo1(32), - regulator_desc_ldo1(33), - regulator_desc_ldo1(34), - regulator_desc_ldo1(35), - regulator_desc_ldo1(36), - regulator_desc_ldo1(37), - regulator_desc_ldo1(38), - regulator_desc_buck1_4(1), - regulator_desc_buck1_4(2), - regulator_desc_buck1_4(3), - regulator_desc_buck1_4(4), - regulator_desc_buck5, - regulator_desc_buck6_8(6), - regulator_desc_buck6_8(7), - regulator_desc_buck6_8(8), - regulator_desc_buck9, - regulator_desc_buck10, + regulator_desc_s2mps11_ldo2(1), + regulator_desc_s2mps11_ldo1(2), + regulator_desc_s2mps11_ldo1(3), + regulator_desc_s2mps11_ldo1(4), + regulator_desc_s2mps11_ldo1(5), + regulator_desc_s2mps11_ldo2(6), + regulator_desc_s2mps11_ldo1(7), + regulator_desc_s2mps11_ldo1(8), + regulator_desc_s2mps11_ldo1(9), + regulator_desc_s2mps11_ldo1(10), + regulator_desc_s2mps11_ldo2(11), + regulator_desc_s2mps11_ldo1(12), + regulator_desc_s2mps11_ldo1(13), + regulator_desc_s2mps11_ldo1(14), + regulator_desc_s2mps11_ldo1(15), + regulator_desc_s2mps11_ldo1(16), + regulator_desc_s2mps11_ldo1(17), + regulator_desc_s2mps11_ldo1(18), + regulator_desc_s2mps11_ldo1(19), + regulator_desc_s2mps11_ldo1(20), + regulator_desc_s2mps11_ldo1(21), + regulator_desc_s2mps11_ldo2(22), + regulator_desc_s2mps11_ldo2(23), + regulator_desc_s2mps11_ldo1(24), + regulator_desc_s2mps11_ldo1(25), + regulator_desc_s2mps11_ldo1(26), + regulator_desc_s2mps11_ldo2(27), + regulator_desc_s2mps11_ldo1(28), + regulator_desc_s2mps11_ldo1(29), + regulator_desc_s2mps11_ldo1(30), + regulator_desc_s2mps11_ldo1(31), + regulator_desc_s2mps11_ldo1(32), + regulator_desc_s2mps11_ldo1(33), + regulator_desc_s2mps11_ldo1(34), + regulator_desc_s2mps11_ldo1(35), + regulator_desc_s2mps11_ldo1(36), + regulator_desc_s2mps11_ldo1(37), + regulator_desc_s2mps11_ldo1(38), + regulator_desc_s2mps11_buck1_4(1), + regulator_desc_s2mps11_buck1_4(2), + regulator_desc_s2mps11_buck1_4(3), + regulator_desc_s2mps11_buck1_4(4), + regulator_desc_s2mps11_buck5, + regulator_desc_s2mps11_buck6_8(6), + regulator_desc_s2mps11_buck6_8(7), + regulator_desc_s2mps11_buck6_8(8), + regulator_desc_s2mps11_buck9, + regulator_desc_s2mps11_buck10, +}; + +static struct regulator_ops s2mps14_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +#define regulator_desc_s2mps14_ldo1(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_800MV, \ + .uV_step = S2MPS14_LDO_STEP_25MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_ldo2(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_1800MV, \ + .uV_step = S2MPS14_LDO_STEP_25MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_ldo3(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_800MV, \ + .uV_step = S2MPS14_LDO_STEP_12_5MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_buck1235(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS14_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_BUCK1235_MIN_600MV, \ + .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \ + .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_buck4(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS14_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_BUCK4_MIN_1400MV, \ + .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .linear_min_sel = S2MPS14_BUCK4_START_SEL, \ + .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} + +static const struct regulator_desc s2mps14_regulators[] = { + regulator_desc_s2mps14_ldo3(1), + regulator_desc_s2mps14_ldo3(2), + regulator_desc_s2mps14_ldo1(3), + regulator_desc_s2mps14_ldo1(4), + regulator_desc_s2mps14_ldo3(5), + regulator_desc_s2mps14_ldo3(6), + regulator_desc_s2mps14_ldo1(7), + regulator_desc_s2mps14_ldo2(8), + regulator_desc_s2mps14_ldo3(9), + regulator_desc_s2mps14_ldo3(10), + regulator_desc_s2mps14_ldo1(11), + regulator_desc_s2mps14_ldo2(12), + regulator_desc_s2mps14_ldo2(13), + regulator_desc_s2mps14_ldo2(14), + regulator_desc_s2mps14_ldo2(15), + regulator_desc_s2mps14_ldo2(16), + regulator_desc_s2mps14_ldo2(17), + regulator_desc_s2mps14_ldo2(18), + regulator_desc_s2mps14_ldo1(19), + regulator_desc_s2mps14_ldo1(20), + regulator_desc_s2mps14_ldo1(21), + regulator_desc_s2mps14_ldo3(22), + regulator_desc_s2mps14_ldo1(23), + regulator_desc_s2mps14_ldo2(24), + regulator_desc_s2mps14_ldo2(25), + regulator_desc_s2mps14_buck1235(1), + regulator_desc_s2mps14_buck1235(2), + regulator_desc_s2mps14_buck1235(3), + regulator_desc_s2mps14_buck4(4), + regulator_desc_s2mps14_buck1235(5), }; static int s2mps11_pmic_probe(struct platform_device *pdev) @@ -416,6 +541,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators); regulators = s2mps11_regulators; break; + case S2MPS14X: + s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators); + regulators = s2mps14_regulators; + break; default: dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); return -EINVAL; @@ -482,6 +611,7 @@ out: static const struct platform_device_id s2mps11_pmic_id[] = { { "s2mps11-pmic", S2MPS11X}, + { "s2mps14-pmic", S2MPS14X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); @@ -509,5 +639,5 @@ module_exit(s2mps11_pmic_exit); /* Module information */ MODULE_AUTHOR("Sangbeom Kim "); -MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver"); +MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 05be09bb5ec8d12051515087a1983745dc93d906 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 7 Mar 2014 11:10:51 +0100 Subject: regulator: s2mps11: Add set_suspend_disable for S2MPS14 S2MPS14 regulators support suspend mode where their status is controlled by PWREN coming from SoC. This patch implements the set_suspend_disable for S2MPS14 regulators. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 51 ++++++++++++++++++++++++++++++++++++- include/linux/mfd/samsung/s2mps14.h | 2 ++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 65697b1a26c0..cdd8d4066121 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -39,6 +39,11 @@ struct s2mps11_info { int ramp_delay16; int ramp_delay7810; int ramp_delay9; + /* + * One bit for each S2MPS14 regulator whether the suspend mode + * was enabled. + */ + unsigned int s2mps14_suspend_state:30; }; static int get_ramp_delay(int ramp_delay) @@ -399,15 +404,59 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_buck10, }; +static int s2mps14_regulator_enable(struct regulator_dev *rdev) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int val; + + if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) + val = S2MPS14_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} + +static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + int ret; + unsigned int val; + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + + /* LDO3 should be always on and does not support suspend mode */ + if (rdev_get_id(rdev) == S2MPS14_LDO3) + return 0; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret < 0) + return ret; + + s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev)); + /* + * Don't enable suspend mode if regulator is already disabled because + * this would effectively for a short time turn on the regulator after + * resuming. + * However we still want to toggle the suspend_state bit for regulator + * in case if it got enabled before suspending the system. + */ + if (!(val & rdev->desc->enable_mask)) + return 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND); +} + static struct regulator_ops s2mps14_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = s2mps14_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = s2mps14_regulator_set_suspend_disable, }; #define regulator_desc_s2mps14_ldo1(num) { \ diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h index ec1e0857ddde..4b449b8ac548 100644 --- a/include/linux/mfd/samsung/s2mps14.h +++ b/include/linux/mfd/samsung/s2mps14.h @@ -146,6 +146,8 @@ enum s2mps14_regulators { #define S2MPS14_BUCK_VSEL_MASK 0xFF #define S2MPS14_ENABLE_MASK (0x03 << S2MPS14_ENABLE_SHIFT) #define S2MPS14_ENABLE_SHIFT 6 +/* On/Off controlled by PWREN */ +#define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT) #define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1) #define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1) -- cgit v1.2.3 From 8d7c7726cea29bd5a7dd6e898b1693c12237144b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 7 Mar 2014 11:10:52 +0100 Subject: Documentation: mfd: s2mps11: Document support for S2MPS14 Add bindings documentation for S2MPS14 device to the s2mps11 driver. Signed-off-by: Krzysztof Kozlowski Cc: Mark Brown Cc: Liam Girdwood Cc: Tomasz Figa Cc: devicetree@vger.kernel.org Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Acked-by: Tomasz Figa Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/mfd/s2mps11.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt index 15ee89c3cc7b..f69bec294f02 100644 --- a/Documentation/devicetree/bindings/mfd/s2mps11.txt +++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt @@ -1,5 +1,5 @@ -* Samsung S2MPS11 Voltage and Current Regulator +* Samsung S2MPS11 and S2MPS14 Voltage and Current Regulator The Samsung S2MPS11 is a multi-function device which includes voltage and current regulators, RTC, charger controller and other sub-blocks. It is @@ -7,7 +7,7 @@ interfaced to the host controller using an I2C interface. Each sub-block is addressed by the host system using different I2C slave addresses. Required properties: -- compatible: Should be "samsung,s2mps11-pmic". +- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic". - reg: Specifies the I2C slave address of the pmic block. It should be 0x66. Optional properties: @@ -59,10 +59,14 @@ supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number as per the datasheet of s2mps11. - LDOn - - valid values for n are 1 to 38 + - valid values for n are: + - S2MPS11: 1 to 38 + - S2MPS14: 1 to 25 - Example: LDO1, LD02, LDO28 - BUCKn - - valid values for n are 1 to 10. + - valid values for n are: + - S2MPS11: 1 to 10 + - S2MPS14: 1 to 5 - Example: BUCK1, BUCK2, BUCK9 Example: -- cgit v1.2.3 From 14256f734ecce8dfb8fdce0e138d18f3fadf882e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 4 Mar 2014 11:16:57 +0530 Subject: regulator: s2mps11: Use of_get_child_by_name of_find_node_by_name walks the allnodes list, and can thus walk outside of the parent node. Use of_get_child_by_name instead. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index cdd8d4066121..906d764e98a8 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -616,7 +616,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) for (i = 0; i < s2mps11->rdev_num; i++) rdata[i].name = regulators[i].name; - reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); + reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators"); if (!reg_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); ret = -EINVAL; -- cgit v1.2.3 From 991acaf629cb12774beb4662e6b3045504680779 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 4 Mar 2014 11:16:58 +0530 Subject: regulator: s2mps11: Add missing of_node_put Add of_node_put to decrement the ref count. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 906d764e98a8..1f6fd4c45006 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -624,6 +624,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); + of_node_put(reg_np); common_reg: platform_set_drvdata(pdev, s2mps11); -- cgit v1.2.3