@@ -24,11 +24,18 @@
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/err.h>
-#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65217.h>
+static struct mfd_cell tps65217s[] = {
+ {
+ .name = "tps65217-pmic",
+ },
+};
+
/**
* tps65217_reg_read: Read a single tps65217 register.
*
@@ -133,83 +140,48 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
-#ifdef CONFIG_OF
-static struct of_regulator_match reg_matches[] = {
- { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
- { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
- { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
- { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
- { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
- { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
- { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
-};
-
-static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
-{
- struct device_node *node = client->dev.of_node;
- struct tps65217_board *pdata;
- struct device_node *regs;
- int count = ARRAY_SIZE(reg_matches);
- int ret, i;
-
- regs = of_find_node_by_name(node, "regulators");
- if (!regs)
- return NULL;
-
- ret = of_regulator_match(&client->dev, regs, reg_matches, count);
- of_node_put(regs);
- if ((ret < 0) || (ret > count))
- return NULL;
-
- count = ret;
- pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- for (i = 0; i < count; i++) {
- if (!reg_matches[i].init_data || !reg_matches[i].of_node)
- continue;
-
- pdata->tps65217_init_data[i] = reg_matches[i].init_data;
- pdata->of_node[i] = reg_matches[i].of_node;
- }
-
- return pdata;
-}
-
-static struct of_device_id tps65217_of_match[] = {
- { .compatible = "ti,tps65217", },
- { },
-};
-#else
-static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
-{
- return NULL;
-}
-#endif
-
static struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
+static const struct of_device_id tps65217_of_match[] = {
+ { .compatible = "ti,tps65217", .data = (void *)TPS65217 },
+ { /* sentinel */ },
+};
+
static int __devinit tps65217_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
{
struct tps65217 *tps;
- struct regulator_init_data *reg_data;
- struct tps65217_board *pdata = client->dev.platform_data;
- int i, ret;
unsigned int version;
+ unsigned int chip_id = ids->driver_data;
+ const struct of_device_id *match;
+ int ret;
- if (!pdata && client->dev.of_node)
- pdata = tps65217_parse_dt(client);
+ if (client->dev.of_node) {
+ match = of_match_device(tps65217_of_match, &client->dev);
+ if (!match) {
+ dev_err(&client->dev,
+ "Failed to find matching dt id\n");
+ return -EINVAL;
+ }
+ chip_id = (unsigned int)match->data;
+ }
+
+ if (!chip_id) {
+ dev_err(&client->dev, "id is null.\n");
+ return -ENODEV;
+ }
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
- tps->pdata = pdata;
+ i2c_set_clientdata(client, tps);
+ tps->dev = &client->dev;
+ tps->id = chip_id;
+
tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
@@ -218,8 +190,12 @@ static int __devinit tps65217_probe(struct i2c_client *client,
return ret;
}
- i2c_set_clientdata(client, tps);
- tps->dev = &client->dev;
+ ret = mfd_add_devices(tps->dev, -1, tps65217s,
+ ARRAY_SIZE(tps65217s), NULL, 0);
+ if (ret < 0) {
+ dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
+ return ret;
+ }
ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
if (ret < 0) {
@@ -232,41 +208,21 @@ static int __devinit tps65217_probe(struct i2c_client *client,
(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
version & TPS65217_CHIPID_REV_MASK);
- for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("tps65217-pmic", i);
- if (!pdev) {
- dev_err(tps->dev, "Cannot create regulator %d\n", i);
- continue;
- }
-
- pdev->dev.parent = tps->dev;
- pdev->dev.of_node = pdata->of_node[i];
- reg_data = pdata->tps65217_init_data[i];
- platform_device_add_data(pdev, reg_data, sizeof(*reg_data));
- tps->regulator_pdev[i] = pdev;
-
- platform_device_add(pdev);
- }
-
return 0;
}
static int __devexit tps65217_remove(struct i2c_client *client)
{
struct tps65217 *tps = i2c_get_clientdata(client);
- int i;
- for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
- platform_device_unregister(tps->regulator_pdev[i]);
+ mfd_remove_devices(tps->dev);
return 0;
}
static const struct i2c_device_id tps65217_id_table[] = {
- {"tps65217", 0xF0},
- {/* end of list */}
+ {"tps65217", TPS65217},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>
@@ -281,37 +282,130 @@ static const struct regulator_desc regulators[] = {
NULL),
};
+#ifdef CONFIG_OF
+static struct of_regulator_match reg_matches[] = {
+ { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
+ { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
+ { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
+ { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
+ { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
+ { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
+ { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
+};
+
+static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
+{
+ struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *node = tps->dev->of_node;
+ struct tps65217_board *pdata;
+ struct device_node *regs;
+ int i, count;
+
+ regs = of_find_node_by_name(node, "regulators");
+ if (!regs)
+ return NULL;
+
+ count = of_regulator_match(pdev->dev.parent, regs,
+ reg_matches, TPS65217_NUM_REGULATOR);
+ of_node_put(regs);
+ if ((count < 0) || (count > TPS65217_NUM_REGULATOR))
+ return NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ for (i = 0; i < count; i++) {
+ if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+ continue;
+
+ pdata->tps65217_init_data[i] = reg_matches[i].init_data;
+ pdata->of_node[i] = reg_matches[i].of_node;
+ }
+
+ return pdata;
+}
+#else
+static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
+{
+ return NULL;
+}
+#endif
+
static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
{
+ struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct tps65217_board *pdata = dev_get_platdata(tps->dev);
+ struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
- struct tps65217 *tps;
- struct tps_info *info = &tps65217_pmic_regs[pdev->id];
struct regulator_config config = { };
+ int i, ret;
- /* Already set by core driver */
- tps = dev_to_tps65217(pdev->dev.parent);
- tps->info[pdev->id] = info;
+ if (tps->dev->of_node)
+ pdata = tps65217_parse_dt(pdev);
- config.dev = &pdev->dev;
- config.of_node = pdev->dev.of_node;
- config.init_data = pdev->dev.platform_data;
- config.driver_data = tps;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Platform data not found\n");
+ return -EINVAL;
+ }
- rdev = regulator_register(®ulators[pdev->id], &config);
- if (IS_ERR(rdev))
- return PTR_ERR(rdev);
+ if (tps65217_chip_id(tps) != TPS65217) {
+ dev_err(&pdev->dev, "Invalid tps chip version\n");
+ return -ENODEV;
+ }
- platform_set_drvdata(pdev, rdev);
+ platform_set_drvdata(pdev, tps);
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+
+ reg_data = pdata->tps65217_init_data[i];
+
+ /*
+ * Regulator API handles empty constraints but not NULL
+ * constraints
+ */
+ if (!reg_data)
+ continue;
+
+ /* Register the regulators */
+ tps->info[i] = &tps65217_pmic_regs[i];
+
+ config.dev = tps->dev;
+ config.init_data = reg_data;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+ if (tps->dev->of_node)
+ config.of_node = pdata->of_node[i];
+
+ rdev = regulator_register(®ulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ ret = PTR_ERR(rdev);
+ goto err_unregister_regulator;
+ }
+
+ /* Save regulator for cleanup */
+ tps->rdev[i] = rdev;
+ }
return 0;
+
+err_unregister_regulator:
+ while (--i >= 0)
+ regulator_unregister(tps->rdev[i]);
+
+ return ret;
}
static int __devexit tps65217_regulator_remove(struct platform_device *pdev)
{
- struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct tps65217 *tps = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+ regulator_unregister(tps->rdev[i]);
platform_set_drvdata(pdev, NULL);
- regulator_unregister(rdev);
return 0;
}
@@ -22,6 +22,9 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+/* TPS chip id list */
+#define TPS65217 0xF0
+
/* I2C ID for TPS65217 part */
#define TPS65217_I2C_ID 0x24
@@ -248,13 +251,11 @@ struct tps_info {
struct tps65217 {
struct device *dev;
struct tps65217_board *pdata;
+ unsigned int id;
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
struct tps_info *info[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
-
- /* Client devices */
- struct platform_device *regulator_pdev[TPS65217_NUM_REGULATOR];
};
static inline struct tps65217 *dev_to_tps65217(struct device *dev)
@@ -262,6 +263,11 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
return dev_get_drvdata(dev);
}
+static inline int tps65217_chip_id(struct tps65217 *tps65217)
+{
+ return tps65217->id;
+}
+
int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
unsigned int *val);
int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
Regulator platform data handling was mistakenly added to MFD driver. So we will see build errors if we compile MFD drivers without CONFIG_REGULATOR. This patch moves regulator platform data handling from TPS65217 MFD driver to regulator driver. This makes MFD driver independent of REGULATOR framework so build error is fixed if CONFIG_REGULATOR is not set. drivers/built-in.o: In function `tps65217_probe': tps65217.c:(.devinit.text+0x13e37): undefined reference to `of_regulator_match' This patch also fix allocation size of tps65217 platform data. Current implementation allocates a struct tps65217_board for each regulator specified in the device tree. But the structure itself provides array of regulators so one instance of it is sufficient. Signed-off-by: AnilKumar Ch <anilkumar@ti.com> --- This patch is tested on BeagleBone with regulator device node additions. And this is based on mfd/master. Changes from v1: - Incorporated Matthias Kaehlcke's commets on v1 * Fixed allocation size of tps65217 platform data drivers/mfd/tps65217.c | 130 +++++++++++--------------------- drivers/regulator/tps65217-regulator.c | 124 ++++++++++++++++++++++++++---- include/linux/mfd/tps65217.h | 12 ++- 3 files changed, 161 insertions(+), 105 deletions(-)