Skip to content

Commit

Permalink
mfd: Move tps65217 regulator plat data handling to regulator
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
AnilKumar Ch authored and Samuel Ortiz committed Aug 22, 2012
1 parent d987569 commit 817bb7f
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 105 deletions.
130 changes: 43 additions & 87 deletions drivers/mfd/tps65217.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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);

Expand Down
124 changes: 109 additions & 15 deletions drivers/regulator/tps65217-regulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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(&regulators[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(&regulators[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;
}
Expand Down
12 changes: 9 additions & 3 deletions include/linux/mfd/tps65217.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -248,20 +251,23 @@ 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)
{
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,
Expand Down

0 comments on commit 817bb7f

Please sign in to comment.