hwmon: (pmbus) Add regulator support

Add support for simple on/off control of each channel.

To add regulator support, the pmbus part driver needs to add
regulator_desc information and number of regulators to its
pmbus_driver_info struct.

regulator_desc can be declared using default macro for a
regulator (PMBUS_REGULATOR) that is in pmbus.h

The regulator_init_data can be initialized from either
platform data or the device tree.

Signed-off-by: Alan Tull <atull@opensource.altera.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Alan Tull 2014-10-15 13:55:09 -05:00 committed by Guenter Roeck
parent 11c119986f
commit ddbb4db4ce
3 changed files with 117 additions and 0 deletions

View File

@ -19,6 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/regulator/driver.h>
#ifndef PMBUS_H #ifndef PMBUS_H
#define PMBUS_H #define PMBUS_H
@ -185,6 +187,11 @@
#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34) #define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34)
#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35) #define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35)
/*
* OPERATION
*/
#define PB_OPERATION_CONTROL_ON (1<<7)
/* /*
* CAPABILITY * CAPABILITY
*/ */
@ -365,8 +372,27 @@ struct pmbus_driver_info {
*/ */
int (*identify)(struct i2c_client *client, int (*identify)(struct i2c_client *client,
struct pmbus_driver_info *info); struct pmbus_driver_info *info);
/* Regulator functionality, if supported by this chip driver. */
int num_regulators;
const struct regulator_desc *reg_desc;
}; };
/* Regulator ops */
extern struct regulator_ops pmbus_regulator_ops;
/* Macro for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR(_name, _id) \
[_id] = { \
.name = (_name # _id), \
.id = (_id), \
.of_match = of_match_ptr(_name # _id), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &pmbus_regulator_ops, \
.owner = THIS_MODULE, \
}
/* Function declarations */ /* Function declarations */
void pmbus_clear_cache(struct i2c_client *client); void pmbus_clear_cache(struct i2c_client *client);

View File

@ -29,6 +29,8 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c/pmbus.h> #include <linux/i2c/pmbus.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include "pmbus.h" #include "pmbus.h"
/* /*
@ -1758,6 +1760,84 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return 0; return 0;
} }
#if IS_ENABLED(CONFIG_REGULATOR)
static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
u8 page = rdev_get_id(rdev);
int ret;
ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
if (ret < 0)
return ret;
return !!(ret & PB_OPERATION_CONTROL_ON);
}
static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
u8 page = rdev_get_id(rdev);
return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
PB_OPERATION_CONTROL_ON,
enable ? PB_OPERATION_CONTROL_ON : 0);
}
static int pmbus_regulator_enable(struct regulator_dev *rdev)
{
return _pmbus_regulator_on_off(rdev, 1);
}
static int pmbus_regulator_disable(struct regulator_dev *rdev)
{
return _pmbus_regulator_on_off(rdev, 0);
}
struct regulator_ops pmbus_regulator_ops = {
.enable = pmbus_regulator_enable,
.disable = pmbus_regulator_disable,
.is_enabled = pmbus_regulator_is_enabled,
};
EXPORT_SYMBOL_GPL(pmbus_regulator_ops);
static int pmbus_regulator_register(struct pmbus_data *data)
{
struct device *dev = data->dev;
const struct pmbus_driver_info *info = data->info;
const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
struct regulator_dev *rdev;
int i;
for (i = 0; i < info->num_regulators; i++) {
struct regulator_config config = { };
config.dev = dev;
config.driver_data = data;
if (pdata && pdata->reg_init_data)
config.init_data = &pdata->reg_init_data[i];
rdev = devm_regulator_register(dev, &info->reg_desc[i],
&config);
if (IS_ERR(rdev)) {
dev_err(dev, "Failed to register %s regulator\n",
info->reg_desc[i].name);
return PTR_ERR(rdev);
}
}
return 0;
}
#else
static int pmbus_regulator_register(struct pmbus_data *data)
{
return 0;
}
#endif
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info) struct pmbus_driver_info *info)
{ {
@ -1812,8 +1892,15 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
dev_err(dev, "Failed to register hwmon device\n"); dev_err(dev, "Failed to register hwmon device\n");
goto out_kfree; goto out_kfree;
} }
ret = pmbus_regulator_register(data);
if (ret)
goto out_unregister;
return 0; return 0;
out_unregister:
hwmon_device_unregister(data->hwmon_dev);
out_kfree: out_kfree:
kfree(data->group.attrs); kfree(data->group.attrs);
return ret; return ret;

View File

@ -40,6 +40,10 @@
struct pmbus_platform_data { struct pmbus_platform_data {
u32 flags; /* Device specific flags */ u32 flags; /* Device specific flags */
/* regulator support */
int num_regulators;
struct regulator_init_data *reg_init_data;
}; };
#endif /* _PMBUS_H_ */ #endif /* _PMBUS_H_ */