|
@@ -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;
|