diff mbox

[v2,1/3] hwmon: (lm90) Add power control

Message ID 1375944991-29182-2-git-send-email-wni@nvidia.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wei Ni Aug. 8, 2013, 6:56 a.m. UTC
The device lm90 can be controlled by the vdd rail.
Adding the power control support to power on/off the vdd rail.
And make sure that power is enabled before accessing the device.

Signed-off-by: Wei Ni <wni@nvidia.com>
---
 drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

Comments

Alexander Shiyan Aug. 8, 2013, 7:13 a.m. UTC | #1
> The device lm90 can be controlled by the vdd rail.
> Adding the power control support to power on/off the vdd rail.
> And make sure that power is enabled before accessing the device.
> 
> Signed-off-by: Wei Ni <wni@nvidia.com>
> ---
>  drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 49 insertions(+)
> 
> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
[...]
> +static void lm90_power_control(struct i2c_client *client, bool is_enable)
> +{
> +	struct lm90_data *data = i2c_get_clientdata(client);
> +	int ret;
> +
> +	if (!data->lm90_reg)
> +		return;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	if (is_enable)
> +		ret = regulator_enable(data->lm90_reg);
> +	else
> +		ret = regulator_disable(data->lm90_reg);
> +
> +	if (ret < 0)
> +		dev_err(&client->dev,
> +			"Error in %s rail vdd, error %d\n",
> +			(is_enable) ? "enabling" : "disabling", ret);
> +	else
> +		dev_info(&client->dev, "success in %s rail vdd\n",
> +			 (is_enable) ? "enabling" : "disabling");

dev_dbg() ?

> +
> +	mutex_unlock(&data->update_lock);
> +}
> +
>  static int lm90_probe(struct i2c_client *client,
>  		      const struct i2c_device_id *id)
>  {
> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>  	i2c_set_clientdata(client, data);
>  	mutex_init(&data->update_lock);
>  
> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {

What about deferred probe?
if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;

> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
> +			dev_info(&client->dev,
> +				 "No regulator found for vdd. Assuming vdd is always powered.");

On my opinion it is unnecessary message.

> +		else
> +			dev_warn(&client->dev,
> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
> +				 PTR_ERR(data->lm90_reg));

Ditto.

> +		data->lm90_reg = NULL;

You can just use !IS_ERR(data->lm90_reg) macro in the future,
rather than set this to NULL.

[...]

---
Guenter Roeck Aug. 8, 2013, 8:42 a.m. UTC | #2
On 08/07/2013 11:56 PM, Wei Ni wrote:
> The device lm90 can be controlled by the vdd rail.
> Adding the power control support to power on/off the vdd rail.
> And make sure that power is enabled before accessing the device.
>
> Signed-off-by: Wei Ni <wni@nvidia.com>
> ---
>   drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 49 insertions(+)
>
> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> index cdff742..306a348 100644
> --- a/drivers/hwmon/lm90.c
> +++ b/drivers/hwmon/lm90.c
> @@ -89,6 +89,7 @@
>   #include <linux/err.h>
>   #include <linux/mutex.h>
>   #include <linux/sysfs.h>
> +#include <linux/regulator/consumer.h>
>
>   /*
>    * Addresses to scan
> @@ -302,6 +303,7 @@ static const struct lm90_params lm90_params[] = {
>   struct lm90_data {
>   	struct device *hwmon_dev;
>   	struct mutex update_lock;
> +	struct regulator *lm90_reg;
>   	char valid; /* zero until following fields are valid */
>   	unsigned long last_updated; /* in jiffies */
>   	int kind;
> @@ -1391,6 +1393,32 @@ static void lm90_init_client(struct i2c_client *client)
>   		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
>   }
>
> +static void lm90_power_control(struct i2c_client *client, bool is_enable)
> +{
> +	struct lm90_data *data = i2c_get_clientdata(client);
> +	int ret;
> +
> +	if (!data->lm90_reg)
> +		return;
> +
> +	mutex_lock(&data->update_lock);
> +

This is only called during probe and remove, so the mutex is unnecessary.

> +	if (is_enable)
> +		ret = regulator_enable(data->lm90_reg);
> +	else
> +		ret = regulator_disable(data->lm90_reg);
> +
> +	if (ret < 0)
> +		dev_err(&client->dev,
> +			"Error in %s rail vdd, error %d\n",
> +			(is_enable) ? "enabling" : "disabling", ret);
> +	else
> +		dev_info(&client->dev, "success in %s rail vdd\n",
> +			 (is_enable) ? "enabling" : "disabling");
> +
which reduces the function to (pretty much unnecessary) messages and an if statement
which you only need because you have the function.

You should just call regulator_enable in probe and regulator_disable in remove.

Guenter

> +	mutex_unlock(&data->update_lock);
> +}
> +
>   static int lm90_probe(struct i2c_client *client,
>   		      const struct i2c_device_id *id)
>   {
> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>   	i2c_set_clientdata(client, data);
>   	mutex_init(&data->update_lock);
>
> +	data->lm90_reg = regulator_get(&client->dev, "vdd");

You should use devm_regulator_get(). Then you also don't need the call to regulator_put().

> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {

The function never returns NULL except if the regulator subsystem is not configured,
so IS_ERR() is more appropriate.

If the regulator subsystem is not configured, you especially don't need or want
to pollute the log with an error message.

> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
> +			dev_info(&client->dev,
> +				 "No regulator found for vdd. Assuming vdd is always powered.");
> +		else
> +			dev_warn(&client->dev,
> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
> +				 PTR_ERR(data->lm90_reg));

I consider the messages unnecessary and confusing. You are polluting the log
of pretty much every PC user who has one of the supported chips in the system,
and of everyone else not using regulators for this chip.

> +		data->lm90_reg = NULL;

As pointed out, this is unnecessary, and you should handle -EPROBE_DEFER correctly.

> +	}
> +
> +	lm90_power_control(client, true);
> +
>   	/* Set the device type */
>   	data->kind = id->driver_data;
>   	if (data->kind == adm1032) {
> @@ -1473,6 +1515,10 @@ exit_remove_files:
>   	lm90_remove_files(client, data);
>   exit_restore:
>   	lm90_restore_conf(client, data);
> +	lm90_power_control(client, false);
> +	if (data->lm90_reg)
> +		regulator_put(data->lm90_reg);
> +
>   	return err;
>   }
>
> @@ -1483,6 +1529,9 @@ static int lm90_remove(struct i2c_client *client)
>   	hwmon_device_unregister(data->hwmon_dev);
>   	lm90_remove_files(client, data);
>   	lm90_restore_conf(client, data);
> +	lm90_power_control(client, false);
> +	if (data->lm90_reg)
> +		regulator_put(data->lm90_reg);
>
>   	return 0;
>   }
>
Wei Ni Aug. 8, 2013, 9:26 a.m. UTC | #3
On 08/08/2013 03:13 PM, Alexander Shiyan wrote:
>> The device lm90 can be controlled by the vdd rail.
>> Adding the power control support to power on/off the vdd rail.
>> And make sure that power is enabled before accessing the device.
>>
>> Signed-off-by: Wei Ni <wni@nvidia.com>
>> ---
>>  drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 49 insertions(+)
>>
>> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> [...]
>> +static void lm90_power_control(struct i2c_client *client, bool is_enable)
>> +{
>> +	struct lm90_data *data = i2c_get_clientdata(client);
>> +	int ret;
>> +
>> +	if (!data->lm90_reg)
>> +		return;
>> +
>> +	mutex_lock(&data->update_lock);
>> +
>> +	if (is_enable)
>> +		ret = regulator_enable(data->lm90_reg);
>> +	else
>> +		ret = regulator_disable(data->lm90_reg);
>> +
>> +	if (ret < 0)
>> +		dev_err(&client->dev,
>> +			"Error in %s rail vdd, error %d\n",
>> +			(is_enable) ? "enabling" : "disabling", ret);
>> +	else
>> +		dev_info(&client->dev, "success in %s rail vdd\n",
>> +			 (is_enable) ? "enabling" : "disabling");
> 
> dev_dbg() ?

As Guenter said, I will remove these messages, and remove this function,
the code will be more clean.

> 
>> +
>> +	mutex_unlock(&data->update_lock);
>> +}
>> +
>>  static int lm90_probe(struct i2c_client *client,
>>  		      const struct i2c_device_id *id)
>>  {
>> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>>  	i2c_set_clientdata(client, data);
>>  	mutex_init(&data->update_lock);
>>  
>> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
>> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {
> 
> What about deferred probe?
> if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
> return -EPROBE_DEFER;

Oh, yes, I should add it.

> 
>> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
>> +			dev_info(&client->dev,
>> +				 "No regulator found for vdd. Assuming vdd is always powered.");
> 
> On my opinion it is unnecessary message.
> 
>> +		else
>> +			dev_warn(&client->dev,
>> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
>> +				 PTR_ERR(data->lm90_reg));
> 
> Ditto.

I will remove these log messages.

> 
>> +		data->lm90_reg = NULL;
> 
> You can just use !IS_ERR(data->lm90_reg) macro in the future,
> rather than set this to NULL.

Yes, it's better, I will do it.

> 
> [...]
> 
> ---
>
Wei Ni Aug. 8, 2013, 9:47 a.m. UTC | #4
On 08/08/2013 04:42 PM, Guenter Roeck wrote:
> On 08/07/2013 11:56 PM, Wei Ni wrote:
>> The device lm90 can be controlled by the vdd rail.
>> Adding the power control support to power on/off the vdd rail.
>> And make sure that power is enabled before accessing the device.
>>
>> Signed-off-by: Wei Ni <wni@nvidia.com>
>> ---
>>   drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 49 insertions(+)
>>
>> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
>> index cdff742..306a348 100644
>> --- a/drivers/hwmon/lm90.c
>> +++ b/drivers/hwmon/lm90.c
>> @@ -89,6 +89,7 @@
>>   #include <linux/err.h>
>>   #include <linux/mutex.h>
>>   #include <linux/sysfs.h>
>> +#include <linux/regulator/consumer.h>
>>
>>   /*
>>    * Addresses to scan
>> @@ -302,6 +303,7 @@ static const struct lm90_params lm90_params[] = {
>>   struct lm90_data {
>>   	struct device *hwmon_dev;
>>   	struct mutex update_lock;
>> +	struct regulator *lm90_reg;
>>   	char valid; /* zero until following fields are valid */
>>   	unsigned long last_updated; /* in jiffies */
>>   	int kind;
>> @@ -1391,6 +1393,32 @@ static void lm90_init_client(struct i2c_client *client)
>>   		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
>>   }
>>
>> +static void lm90_power_control(struct i2c_client *client, bool is_enable)
>> +{
>> +	struct lm90_data *data = i2c_get_clientdata(client);
>> +	int ret;
>> +
>> +	if (!data->lm90_reg)
>> +		return;
>> +
>> +	mutex_lock(&data->update_lock);
>> +
> 
> This is only called during probe and remove, so the mutex is unnecessary.

I considered that we may call this function in suspend/resume routine,
so I add this mutex.
But as you said, currently we doesn't have these routine yet, the mutex
is unnecessary, so I will remove it.

> 
>> +	if (is_enable)
>> +		ret = regulator_enable(data->lm90_reg);
>> +	else
>> +		ret = regulator_disable(data->lm90_reg);
>> +
>> +	if (ret < 0)
>> +		dev_err(&client->dev,
>> +			"Error in %s rail vdd, error %d\n",
>> +			(is_enable) ? "enabling" : "disabling", ret);
>> +	else
>> +		dev_info(&client->dev, "success in %s rail vdd\n",
>> +			 (is_enable) ? "enabling" : "disabling");
>> +
> which reduces the function to (pretty much unnecessary) messages and an if statement
> which you only need because you have the function.
> 
> You should just call regulator_enable in probe and regulator_disable in remove.

Ok, I will remove these messages and this function.

> 
> Guenter
> 
>> +	mutex_unlock(&data->update_lock);
>> +}
>> +
>>   static int lm90_probe(struct i2c_client *client,
>>   		      const struct i2c_device_id *id)
>>   {
>> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>>   	i2c_set_clientdata(client, data);
>>   	mutex_init(&data->update_lock);
>>
>> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
> 
> You should use devm_regulator_get(). Then you also don't need the call to regulator_put().

Oh, yes, you are right, I will do it.

> 
>> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {
> 
> The function never returns NULL except if the regulator subsystem is not configured,
> so IS_ERR() is more appropriate.
> 
> If the regulator subsystem is not configured, you especially don't need or want
> to pollute the log with an error message.
> 
>> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
>> +			dev_info(&client->dev,
>> +				 "No regulator found for vdd. Assuming vdd is always powered.");
>> +		else
>> +			dev_warn(&client->dev,
>> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
>> +				 PTR_ERR(data->lm90_reg));
> 
> I consider the messages unnecessary and confusing. You are polluting the log
> of pretty much every PC user who has one of the supported chips in the system,
> and of everyone else not using regulators for this chip.

Ok, I will remove these codes.
So I will write something like:
if (!IS_ERR(data->lm90_reg)) {
    ret = regulator_enable(data->lm90_reg);
    if (ret < 0) {
        dev_err();
        return ret;
    }
} else {
    if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
        return -EPRPBE_DEFER;

        data->lm90_reg = !!IS_ERR(data->lm90_reg);
}

> 
>> +		data->lm90_reg = NULL;
> 
> As pointed out, this is unnecessary, and you should handle -EPROBE_DEFER correctly.

I think get_regulator() will return error values, not only
-EPROBE_DEFER, so we should set data->lm90_reg to NULL to handle other
error values.

> 
>> +	}
>> +
>> +	lm90_power_control(client, true);
>> +
>>   	/* Set the device type */
>>   	data->kind = id->driver_data;
>>   	if (data->kind == adm1032) {
>> @@ -1473,6 +1515,10 @@ exit_remove_files:
>>   	lm90_remove_files(client, data);
>>   exit_restore:
>>   	lm90_restore_conf(client, data);
>> +	lm90_power_control(client, false);
>> +	if (data->lm90_reg)
>> +		regulator_put(data->lm90_reg);
>> +
>>   	return err;
>>   }
>>
>> @@ -1483,6 +1529,9 @@ static int lm90_remove(struct i2c_client *client)
>>   	hwmon_device_unregister(data->hwmon_dev);
>>   	lm90_remove_files(client, data);
>>   	lm90_restore_conf(client, data);
>> +	lm90_power_control(client, false);
>> +	if (data->lm90_reg)
>> +		regulator_put(data->lm90_reg);
>>
>>   	return 0;
>>   }
>>
>
Alexander Shiyan Aug. 8, 2013, 9:57 a.m. UTC | #5
> On 08/08/2013 04:42 PM, Guenter Roeck wrote:
> > On 08/07/2013 11:56 PM, Wei Ni wrote:
> >> The device lm90 can be controlled by the vdd rail.
> >> Adding the power control support to power on/off the vdd rail.
> >> And make sure that power is enabled before accessing the device.
> >>
> >> Signed-off-by: Wei Ni <wni@nvidia.com>
> >> ---
> >>   drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
[...]
> > I consider the messages unnecessary and confusing. You are polluting the log
> > of pretty much every PC user who has one of the supported chips in the system,
> > and of everyone else not using regulators for this chip.
> 
> Ok, I will remove these codes.
> So I will write something like:
> if (!IS_ERR(data->lm90_reg)) {
>     ret = regulator_enable(data->lm90_reg);
>     if (ret < 0) {
>         dev_err();
>         return ret;
>     }
> } else {
>     if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
>         return -EPRPBE_DEFER;
> 
>         data->lm90_reg = !!IS_ERR(data->lm90_reg);

No. You do not need this line.

Just use in remove():
if (!IS_ERR(data->lm90_reg))
regulator_disable(data->lm90_reg);

---
Wei Ni Aug. 8, 2013, 9:59 a.m. UTC | #6
On 08/08/2013 05:57 PM, Alexander Shiyan wrote:
>> On 08/08/2013 04:42 PM, Guenter Roeck wrote:
>>> On 08/07/2013 11:56 PM, Wei Ni wrote:
>>>> The device lm90 can be controlled by the vdd rail.
>>>> Adding the power control support to power on/off the vdd rail.
>>>> And make sure that power is enabled before accessing the device.
>>>>
>>>> Signed-off-by: Wei Ni <wni@nvidia.com>
>>>> ---
>>>>   drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
> [...]
>>> I consider the messages unnecessary and confusing. You are polluting the log
>>> of pretty much every PC user who has one of the supported chips in the system,
>>> and of everyone else not using regulators for this chip.
>>
>> Ok, I will remove these codes.
>> So I will write something like:
>> if (!IS_ERR(data->lm90_reg)) {
>>     ret = regulator_enable(data->lm90_reg);
>>     if (ret < 0) {
>>         dev_err();
>>         return ret;
>>     }
>> } else {
>>     if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
>>         return -EPRPBE_DEFER;
>>
>>         data->lm90_reg = !!IS_ERR(data->lm90_reg);
> 
> No. You do not need this line.
> 
> Just use in remove():
> if (!IS_ERR(data->lm90_reg))
> regulator_disable(data->lm90_reg);

Oh, I see, thank you very much.

> 
> ---
>
Wei Ni Aug. 8, 2013, 10:07 a.m. UTC | #7
On 08/08/2013 05:57 PM, Alexander Shiyan wrote:
>> On 08/08/2013 04:42 PM, Guenter Roeck wrote:
>>> On 08/07/2013 11:56 PM, Wei Ni wrote:
>>>> The device lm90 can be controlled by the vdd rail.
>>>> Adding the power control support to power on/off the vdd rail.
>>>> And make sure that power is enabled before accessing the device.
>>>>
>>>> Signed-off-by: Wei Ni <wni@nvidia.com>
>>>> ---
>>>>   drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
> [...]
>>> I consider the messages unnecessary and confusing. You are polluting the log
>>> of pretty much every PC user who has one of the supported chips in the system,
>>> and of everyone else not using regulators for this chip.
>>
>> Ok, I will remove these codes.
>> So I will write something like:
>> if (!IS_ERR(data->lm90_reg)) {
>>     ret = regulator_enable(data->lm90_reg);
>>     if (ret < 0) {
>>         dev_err();
>>         return ret;
>>     }
>> } else {
>>     if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
>>         return -EPRPBE_DEFER;
>>
>>         data->lm90_reg = !!IS_ERR(data->lm90_reg);

BTW, since it may return EPROBE_DEFER, these codes should be put in the
beginning of the probe() function, should before allocate lm90_data.

> 
> No. You do not need this line.
> 
> Just use in remove():
> if (!IS_ERR(data->lm90_reg))
> regulator_disable(data->lm90_reg);
> 
> ---
>
Mark Brown Aug. 8, 2013, 11:01 a.m. UTC | #8
On Thu, Aug 08, 2013 at 02:56:29PM +0800, Wei Ni wrote:

> +	mutex_lock(&data->update_lock);
> +
> +	if (is_enable)
> +		ret = regulator_enable(data->lm90_reg);
> +	else
> +		ret = regulator_disable(data->lm90_reg);
> +
> +	if (ret < 0)
> +		dev_err(&client->dev,
> +			"Error in %s rail vdd, error %d\n",
> +			(is_enable) ? "enabling" : "disabling", ret);
> +	else
> +		dev_info(&client->dev, "success in %s rail vdd\n",
> +			 (is_enable) ? "enabling" : "disabling");
> +
> +	mutex_unlock(&data->update_lock);

Two things here.  One is that it's not clear what this lokc is
protecting since the only thing in the locked region is the regulator
operation and that is thread safe.  The other thing is that I'm not
seeing anthing that ensures that enables and disables are matched -
regulators are reference counted so two enables need two disables.

> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {

NULL is a valid regulator, use IS_ERR().

> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
> +			dev_info(&client->dev,
> +				 "No regulator found for vdd. Assuming vdd is always powered.");
> +		else
> +			dev_warn(&client->dev,
> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
> +				 PTR_ERR(data->lm90_reg));

You shouldn't just be ignoring errors here, though there are deployment
difficulties with making sure a stub regulator is provided.  These
should be getting easier after the next merge window, the stubs will be
being tweaked slightly to have an "assume it's there" option even when
regulators are used.  Especially in cases with device tree you should be
paying attention to -EPROBE_DEFER, that will accurately reflect if a
regulator is present but not loaded yet.

That said if you *are* going to do this you should request the
regulator using devm_regulator_get_optional(), this is intended to
support things that don't need regulators (though that's not the case
here).
Guenter Roeck Aug. 8, 2013, 11:23 a.m. UTC | #9
On 08/08/2013 02:47 AM, Wei Ni wrote:
> On 08/08/2013 04:42 PM, Guenter Roeck wrote:
>> On 08/07/2013 11:56 PM, Wei Ni wrote:
>>> The device lm90 can be controlled by the vdd rail.
>>> Adding the power control support to power on/off the vdd rail.
>>> And make sure that power is enabled before accessing the device.
>>>
>>> Signed-off-by: Wei Ni <wni@nvidia.com>
>>> ---
>>>    drivers/hwmon/lm90.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>    1 file changed, 49 insertions(+)
>>>
>>> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
>>> index cdff742..306a348 100644
>>> --- a/drivers/hwmon/lm90.c
>>> +++ b/drivers/hwmon/lm90.c
>>> @@ -89,6 +89,7 @@
>>>    #include <linux/err.h>
>>>    #include <linux/mutex.h>
>>>    #include <linux/sysfs.h>
>>> +#include <linux/regulator/consumer.h>
>>>
>>>    /*
>>>     * Addresses to scan
>>> @@ -302,6 +303,7 @@ static const struct lm90_params lm90_params[] = {
>>>    struct lm90_data {
>>>    	struct device *hwmon_dev;
>>>    	struct mutex update_lock;
>>> +	struct regulator *lm90_reg;
>>>    	char valid; /* zero until following fields are valid */
>>>    	unsigned long last_updated; /* in jiffies */
>>>    	int kind;
>>> @@ -1391,6 +1393,32 @@ static void lm90_init_client(struct i2c_client *client)
>>>    		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
>>>    }
>>>
>>> +static void lm90_power_control(struct i2c_client *client, bool is_enable)
>>> +{
>>> +	struct lm90_data *data = i2c_get_clientdata(client);
>>> +	int ret;
>>> +
>>> +	if (!data->lm90_reg)
>>> +		return;
>>> +
>>> +	mutex_lock(&data->update_lock);
>>> +
>>
>> This is only called during probe and remove, so the mutex is unnecessary.
>
> I considered that we may call this function in suspend/resume routine,
> so I add this mutex.
> But as you said, currently we doesn't have these routine yet, the mutex
> is unnecessary, so I will remove it.
>
In that case, you can call
	mutex_lock()
	regulator_enable() / regulator_disable()
	mutex_unlock()

directly in those functions. Again no need for the additional function.

>>
>>> +	if (is_enable)
>>> +		ret = regulator_enable(data->lm90_reg);
>>> +	else
>>> +		ret = regulator_disable(data->lm90_reg);
>>> +
>>> +	if (ret < 0)
>>> +		dev_err(&client->dev,
>>> +			"Error in %s rail vdd, error %d\n",
>>> +			(is_enable) ? "enabling" : "disabling", ret);
>>> +	else
>>> +		dev_info(&client->dev, "success in %s rail vdd\n",
>>> +			 (is_enable) ? "enabling" : "disabling");
>>> +
>> which reduces the function to (pretty much unnecessary) messages and an if statement
>> which you only need because you have the function.
>>
>> You should just call regulator_enable in probe and regulator_disable in remove.
>
> Ok, I will remove these messages and this function.
>
>>
>> Guenter
>>
>>> +	mutex_unlock(&data->update_lock);
>>> +}
>>> +
>>>    static int lm90_probe(struct i2c_client *client,
>>>    		      const struct i2c_device_id *id)
>>>    {
>>> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>>>    	i2c_set_clientdata(client, data);
>>>    	mutex_init(&data->update_lock);
>>>
>>> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
>>
>> You should use devm_regulator_get(). Then you also don't need the call to regulator_put().
>
> Oh, yes, you are right, I will do it.
>
>>
>>> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {
>>
>> The function never returns NULL except if the regulator subsystem is not configured,
>> so IS_ERR() is more appropriate.
>>
>> If the regulator subsystem is not configured, you especially don't need or want
>> to pollute the log with an error message.
>>
>>> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
>>> +			dev_info(&client->dev,
>>> +				 "No regulator found for vdd. Assuming vdd is always powered.");
>>> +		else
>>> +			dev_warn(&client->dev,
>>> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
>>> +				 PTR_ERR(data->lm90_reg));
>>
>> I consider the messages unnecessary and confusing. You are polluting the log
>> of pretty much every PC user who has one of the supported chips in the system,
>> and of everyone else not using regulators for this chip.
>
> Ok, I will remove these codes.
> So I will write something like:
> if (!IS_ERR(data->lm90_reg)) {
>      ret = regulator_enable(data->lm90_reg);
>      if (ret < 0) {
>          dev_err();
>          return ret;
>      }
> } else {

Handle the error in the if case.

>      if (PTR_ERR(data->lm90_reg) == -EPROBE_DEFER)
>          return -EPRPBE_DEFER;
>
>          data->lm90_reg = !!IS_ERR(data->lm90_reg);

You know that IS_ERR is true here. Unless I am missing something, this would assign "1" to lm90_reg.

> }
>
>>
>>> +		data->lm90_reg = NULL;
>>
>> As pointed out, this is unnecessary, and you should handle -EPROBE_DEFER correctly.
>
> I think get_regulator() will return error values, not only
> -EPROBE_DEFER, so we should set data->lm90_reg to NULL to handle other
> error values.
>
Matter of opinion if you want to check for IS_ERR or NULL later on.

>>
>>> +	}
>>> +
>>> +	lm90_power_control(client, true);
>>> +
>>>    	/* Set the device type */
>>>    	data->kind = id->driver_data;
>>>    	if (data->kind == adm1032) {
>>> @@ -1473,6 +1515,10 @@ exit_remove_files:
>>>    	lm90_remove_files(client, data);
>>>    exit_restore:
>>>    	lm90_restore_conf(client, data);
>>> +	lm90_power_control(client, false);
>>> +	if (data->lm90_reg)
>>> +		regulator_put(data->lm90_reg);
>>> +
>>>    	return err;
>>>    }
>>>
>>> @@ -1483,6 +1529,9 @@ static int lm90_remove(struct i2c_client *client)
>>>    	hwmon_device_unregister(data->hwmon_dev);
>>>    	lm90_remove_files(client, data);
>>>    	lm90_restore_conf(client, data);
>>> +	lm90_power_control(client, false);
>>> +	if (data->lm90_reg)
>>> +		regulator_put(data->lm90_reg);
>>>
>>>    	return 0;
>>>    }
>>>
>>
>
>
>
Guenter Roeck Aug. 8, 2013, 11:25 a.m. UTC | #10
On 08/08/2013 04:01 AM, Mark Brown wrote:
> On Thu, Aug 08, 2013 at 02:56:29PM +0800, Wei Ni wrote:
>
>> +	mutex_lock(&data->update_lock);
>> +
>> +	if (is_enable)
>> +		ret = regulator_enable(data->lm90_reg);
>> +	else
>> +		ret = regulator_disable(data->lm90_reg);
>> +
>> +	if (ret < 0)
>> +		dev_err(&client->dev,
>> +			"Error in %s rail vdd, error %d\n",
>> +			(is_enable) ? "enabling" : "disabling", ret);
>> +	else
>> +		dev_info(&client->dev, "success in %s rail vdd\n",
>> +			 (is_enable) ? "enabling" : "disabling");
>> +
>> +	mutex_unlock(&data->update_lock);
>
> Two things here.  One is that it's not clear what this lokc is
> protecting since the only thing in the locked region is the regulator
> operation and that is thread safe.  The other thing is that I'm not
> seeing anthing that ensures that enables and disables are matched -
> regulators are reference counted so two enables need two disables.
>
>> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
>> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {
>
> NULL is a valid regulator, use IS_ERR().
>
>> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
>> +			dev_info(&client->dev,
>> +				 "No regulator found for vdd. Assuming vdd is always powered.");
>> +		else
>> +			dev_warn(&client->dev,
>> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
>> +				 PTR_ERR(data->lm90_reg));
>
> You shouldn't just be ignoring errors here, though there are deployment
> difficulties with making sure a stub regulator is provided.  These
> should be getting easier after the next merge window, the stubs will be
> being tweaked slightly to have an "assume it's there" option even when
> regulators are used.  Especially in cases with device tree you should be
> paying attention to -EPROBE_DEFER, that will accurately reflect if a
> regulator is present but not loaded yet.
>
> That said if you *are* going to do this you should request the
> regulator using devm_regulator_get_optional(), this is intended to
> support things that don't need regulators (though that's not the case
> here).
>
The lm90 driver works perfectly fine without regulator.

Guenter
Mark Brown Aug. 8, 2013, 1:08 p.m. UTC | #11
On Thu, Aug 08, 2013 at 04:25:41AM -0700, Guenter Roeck wrote:
> On 08/08/2013 04:01 AM, Mark Brown wrote:

> >That said if you *are* going to do this you should request the
> >regulator using devm_regulator_get_optional(), this is intended to
> >support things that don't need regulators (though that's not the case
> >here).

> The lm90 driver works perfectly fine without regulator.

I'd be most surprised if the device worked without power, if the driver
fails to get and enable a regulator for it then that's not great
(especially if it does so silently).

Note that the regulator API is written to stub itself out if not
enabled, the code should be able to assume that it's there.
Guenter Roeck Aug. 8, 2013, 3:21 p.m. UTC | #12
On 08/08/2013 06:08 AM, Mark Brown wrote:
> On Thu, Aug 08, 2013 at 04:25:41AM -0700, Guenter Roeck wrote:
>> On 08/08/2013 04:01 AM, Mark Brown wrote:
>
>>> That said if you *are* going to do this you should request the
>>> regulator using devm_regulator_get_optional(), this is intended to
>>> support things that don't need regulators (though that's not the case
>>> here).
>
>> The lm90 driver works perfectly fine without regulator.
>
> I'd be most surprised if the device worked without power, if the driver
> fails to get and enable a regulator for it then that's not great
> (especially if it does so silently).
>
Correct, but it appears that the driver magically worked for a long time
without it.

Is it guaranteed that the driver keeps working for all cases where
regulator support is enabled in the kernel, and where it used to work
so far without mandating the existence of this specific regulator ?
My main concern is having to deal with complaints that the driver stopped
working for no good reason.

In this context, is it common practice to name such regulators "vdd"
or similar ? What if there are multiple LM90 or compatible chips
in a system, connected to different power rails ? Who determines
if the regulator is supposed to be named "vdd" or "vcc" or anything
else, and to which power rails it is actually connected ? How can
and does one guarantee that "vdd" is the correct regulator to use
for all systems ? What if some other driver requests "vdd", but the chip
it supports happens to be connected to a different power rail ?

Sorry for my ignorance in that matter. I did browse through Documentation/power,
but did not find a clear answer.

> Note that the regulator API is written to stub itself out if not
> enabled, the code should be able to assume that it's there.
>
I am aware of that; this is why the driver should not dump an error message
if the function returns NULL and bail out, as it did originally.

Guenter
Mark Brown Aug. 8, 2013, 5:15 p.m. UTC | #13
On Thu, Aug 08, 2013 at 08:21:48AM -0700, Guenter Roeck wrote:
> On 08/08/2013 06:08 AM, Mark Brown wrote:

> >I'd be most surprised if the device worked without power, if the driver
> >fails to get and enable a regulator for it then that's not great
> >(especially if it does so silently).

> Correct, but it appears that the driver magically worked for a long time
> without it.

Sure, it'll work in systems that have always on regulators.

> Is it guaranteed that the driver keeps working for all cases where
> regulator support is enabled in the kernel, and where it used to work
> so far without mandating the existence of this specific regulator ?
> My main concern is having to deal with complaints that the driver stopped
> working for no good reason.

Sure, that's the transition issues I mentioned - the regulator API does
have stubbing facilities which should cover things and it's very easy to
define stub regulators if you need to.  Like I say I expect this to be a
lot easier after the next merge window as another way of doing stubs is
being added which should make this even easier by avoiding disrupting
drivers that do genuinely want to check for absent supplies and handle
that better.

> In this context, is it common practice to name such regulators "vdd"
> or similar ? What if there are multiple LM90 or compatible chips
> in a system, connected to different power rails ? Who determines
> if the regulator is supposed to be named "vdd" or "vcc" or anything
> else, and to which power rails it is actually connected ? How can
> and does one guarantee that "vdd" is the correct regulator to use
> for all systems ? What if some other driver requests "vdd", but the chip
> it supports happens to be connected to a different power rail ?

That's not what the name means - they are nothing to do with the board.
The names requested by a driver are defined with regard to the device
and should be the names used by the chip itself as defined in the
datasheet.  A board that uses regulators then maps these onto specific
regulators in the system, the driver doesn't need to know anything about
this process.
Stephen Warren Aug. 8, 2013, 5:30 p.m. UTC | #14
On 08/08/2013 02:42 AM, Guenter Roeck wrote:
> On 08/07/2013 11:56 PM, Wei Ni wrote:
>> The device lm90 can be controlled by the vdd rail.
>> Adding the power control support to power on/off the vdd rail.
>> And make sure that power is enabled before accessing the device.

>> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c

>>   static int lm90_probe(struct i2c_client *client,
>>                 const struct i2c_device_id *id)
>>   {
>> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
>>       i2c_set_clientdata(client, data);
>>       mutex_init(&data->update_lock);
>>
>> +    data->lm90_reg = regulator_get(&client->dev, "vdd");
> 
> You should use devm_regulator_get(). Then you also don't need the call
> to regulator_put().
> 
>> +    if (IS_ERR_OR_NULL(data->lm90_reg)) {
> 
> The function never returns NULL except if the regulator subsystem is not
> configured,
> so IS_ERR() is more appropriate.
> 
> If the regulator subsystem is not configured, you especially don't need
> or want
> to pollute the log with an error message.

DT parsing errors should be reported. However, if there's nothing to
parse, it's not an error.

So, I think this should report an error message *if* there is a DT
property that defines the regulator to use. If there's no property, just
use no regulator. If there is a property, it had better be possible to
parse it.
Stephen Warren Aug. 8, 2013, 5:33 p.m. UTC | #15
On 08/08/2013 05:23 AM, Guenter Roeck wrote:
> On 08/08/2013 02:47 AM, Wei Ni wrote:
...
>> I think get_regulator() will return error values, not only
>> -EPROBE_DEFER, so we should set data->lm90_reg to NULL to handle other
>> error values.
>>
> Matter of opinion if you want to check for IS_ERR or NULL later on.

No, if regulator returns either:

* Something valid
* Someting IS_ERR()

... then everywhere has to check the value using IS_ERR().

If regulator returns either:

* Something valid
* Someting NULL

... then everywhere has to check the value against NULL.

checking against both IS_ERR() and NULL shouldn't ever happen, and
likewise IS_ERR_OR_NULL() is deprecated.
Guenter Roeck Aug. 8, 2013, 5:59 p.m. UTC | #16
On Thu, Aug 08, 2013 at 11:33:13AM -0600, Stephen Warren wrote:
> On 08/08/2013 05:23 AM, Guenter Roeck wrote:
> > On 08/08/2013 02:47 AM, Wei Ni wrote:
> ...
> >> I think get_regulator() will return error values, not only
> >> -EPROBE_DEFER, so we should set data->lm90_reg to NULL to handle other
> >> error values.
> >>
> > Matter of opinion if you want to check for IS_ERR or NULL later on.
> 
> No, if regulator returns either:
> 
> * Something valid
> * Someting IS_ERR()
> 
> ... then everywhere has to check the value using IS_ERR().
> 
> If regulator returns either:
> 
> * Something valid
> * Someting NULL
> 
> ... then everywhere has to check the value against NULL.
> 
Other drivers calling get_regulator() don't check against NULL,
so it should not be needed here either.

Guenter

> checking against both IS_ERR() and NULL shouldn't ever happen, and
> likewise IS_ERR_OR_NULL() is deprecated.
>
Guenter Roeck Aug. 8, 2013, 5:59 p.m. UTC | #17
On Thu, Aug 08, 2013 at 11:30:30AM -0600, Stephen Warren wrote:
> On 08/08/2013 02:42 AM, Guenter Roeck wrote:
> > On 08/07/2013 11:56 PM, Wei Ni wrote:
> >> The device lm90 can be controlled by the vdd rail.
> >> Adding the power control support to power on/off the vdd rail.
> >> And make sure that power is enabled before accessing the device.
> 
> >> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> 
> >>   static int lm90_probe(struct i2c_client *client,
> >>                 const struct i2c_device_id *id)
> >>   {
> >> @@ -1406,6 +1434,20 @@ static int lm90_probe(struct i2c_client *client,
> >>       i2c_set_clientdata(client, data);
> >>       mutex_init(&data->update_lock);
> >>
> >> +    data->lm90_reg = regulator_get(&client->dev, "vdd");
> > 
> > You should use devm_regulator_get(). Then you also don't need the call
> > to regulator_put().
> > 
> >> +    if (IS_ERR_OR_NULL(data->lm90_reg)) {
> > 
> > The function never returns NULL except if the regulator subsystem is not
> > configured,
> > so IS_ERR() is more appropriate.
> > 
> > If the regulator subsystem is not configured, you especially don't need
> > or want
> > to pollute the log with an error message.
> 
> DT parsing errors should be reported. However, if there's nothing to
> parse, it's not an error.
> 
> So, I think this should report an error message *if* there is a DT
> property that defines the regulator to use. If there's no property, just
> use no regulator. If there is a property, it had better be possible to
> parse it.
> 
Agreed.

Guenter
Stephen Warren Aug. 8, 2013, 6:45 p.m. UTC | #18
On 08/08/2013 11:59 AM, Guenter Roeck wrote:
> On Thu, Aug 08, 2013 at 11:33:13AM -0600, Stephen Warren wrote:
>> On 08/08/2013 05:23 AM, Guenter Roeck wrote:
>>> On 08/08/2013 02:47 AM, Wei Ni wrote:
>> ...
>>>> I think get_regulator() will return error values, not only
>>>> -EPROBE_DEFER, so we should set data->lm90_reg to NULL to handle other
>>>> error values.
>>>>
>>> Matter of opinion if you want to check for IS_ERR or NULL later on.
>>
>> No, if regulator returns either:
>>
>> * Something valid
>> * Someting IS_ERR()
>>
>> ... then everywhere has to check the value using IS_ERR().
>>
>> If regulator returns either:
>>
>> * Something valid
>> * Someting NULL
>>
>> ... then everywhere has to check the value against NULL.
>>
> Other drivers calling get_regulator() don't check against NULL,
> so it should not be needed here either.

Right I should have mentioned that I believe regulator falls into the
first valid-or-IS_ERR case, and not the second valid-or-NULL case.
Mark Brown Aug. 8, 2013, 7:27 p.m. UTC | #19
On Thu, Aug 08, 2013 at 11:30:30AM -0600, Stephen Warren wrote:
> On 08/08/2013 02:42 AM, Guenter Roeck wrote:

> > If the regulator subsystem is not configured, you especially don't need
> > or want
> > to pollute the log with an error message.

> DT parsing errors should be reported. However, if there's nothing to
> parse, it's not an error.

> So, I think this should report an error message *if* there is a DT
> property that defines the regulator to use. If there's no property, just
> use no regulator. If there is a property, it had better be possible to
> parse it.

On a DT system you should get this behaviour simply by paying attention
to the error code from the regualtor API - the core should complain
loudly if the DT is incomprehensible.
Guenter Roeck Aug. 8, 2013, 8 p.m. UTC | #20
On Thu, Aug 08, 2013 at 06:15:54PM +0100, Mark Brown wrote:
> On Thu, Aug 08, 2013 at 08:21:48AM -0700, Guenter Roeck wrote:
> > On 08/08/2013 06:08 AM, Mark Brown wrote:
> 
> > >I'd be most surprised if the device worked without power, if the driver
> > >fails to get and enable a regulator for it then that's not great
> > >(especially if it does so silently).
> 
> > Correct, but it appears that the driver magically worked for a long time
> > without it.
> 
> Sure, it'll work in systems that have always on regulators.
> 
> > Is it guaranteed that the driver keeps working for all cases where
> > regulator support is enabled in the kernel, and where it used to work
> > so far without mandating the existence of this specific regulator ?
> > My main concern is having to deal with complaints that the driver stopped
> > working for no good reason.
> 
> Sure, that's the transition issues I mentioned - the regulator API does
> have stubbing facilities which should cover things and it's very easy to
> define stub regulators if you need to.  Like I say I expect this to be a
> lot easier after the next merge window as another way of doing stubs is
> being added which should make this even easier by avoiding disrupting
> drivers that do genuinely want to check for absent supplies and handle
> that better.
> 
We will need to make sure that all dts files using any of the compatible chips
are updated accordingly. There are several entries in various dts files for
adm1032, adt7461, lm90, and nct1008.

> > In this context, is it common practice to name such regulators "vdd"
> > or similar ? What if there are multiple LM90 or compatible chips
> > in a system, connected to different power rails ? Who determines
> > if the regulator is supposed to be named "vdd" or "vcc" or anything
> > else, and to which power rails it is actually connected ? How can
> > and does one guarantee that "vdd" is the correct regulator to use
> > for all systems ? What if some other driver requests "vdd", but the chip
> > it supports happens to be connected to a different power rail ?
> 
> That's not what the name means - they are nothing to do with the board.

Ok, makes sense.

> The names requested by a driver are defined with regard to the device
> and should be the names used by the chip itself as defined in the

9 votes for vdd, 11 votes for vcc, one undecided (no datasheet available).
Guess one is as good as the other ;-).

Guenter

> datasheet.  A board that uses regulators then maps these onto specific
> regulators in the system, the driver doesn't need to know anything about
> this process.
Mark Brown Aug. 8, 2013, 9:18 p.m. UTC | #21
On Thu, Aug 08, 2013 at 01:00:26PM -0700, Guenter Roeck wrote:
> On Thu, Aug 08, 2013 at 06:15:54PM +0100, Mark Brown wrote:

> > Sure, that's the transition issues I mentioned - the regulator API does
> > have stubbing facilities which should cover things and it's very easy to
> > define stub regulators if you need to.  Like I say I expect this to be a
> > lot easier after the next merge window as another way of doing stubs is
> > being added which should make this even easier by avoiding disrupting
> > drivers that do genuinely want to check for absent supplies and handle
> > that better.

> We will need to make sure that all dts files using any of the compatible chips
> are updated accordingly. There are several entries in various dts files for
> adm1032, adt7461, lm90, and nct1008.

Yes, and probably also board files as well.  Or either just accept
bisection trouble for now or wait till the better stubbing is in there -
that will mean that for DT systems the core will just assume the supply
is really there and not fail requests if it's not in the DT.

> > The names requested by a driver are defined with regard to the device
> > and should be the names used by the chip itself as defined in the

> 9 votes for vdd, 11 votes for vcc, one undecided (no datasheet available).
> Guess one is as good as the other ;-).

What I've suggested before is to use the name from the part for which
the driver is named.  Assuming the vendor doesn't randomly change their
datasheet (but that causes problems for hardware engineers so tends to
be avoided).
Guenter Roeck Aug. 8, 2013, 9:30 p.m. UTC | #22
On 08/08/2013 02:18 PM, Mark Brown wrote:
> On Thu, Aug 08, 2013 at 01:00:26PM -0700, Guenter Roeck wrote:
>> On Thu, Aug 08, 2013 at 06:15:54PM +0100, Mark Brown wrote:
>
>>> Sure, that's the transition issues I mentioned - the regulator API does
>>> have stubbing facilities which should cover things and it's very easy to
>>> define stub regulators if you need to.  Like I say I expect this to be a
>>> lot easier after the next merge window as another way of doing stubs is
>>> being added which should make this even easier by avoiding disrupting
>>> drivers that do genuinely want to check for absent supplies and handle
>>> that better.
>
>> We will need to make sure that all dts files using any of the compatible chips
>> are updated accordingly. There are several entries in various dts files for
>> adm1032, adt7461, lm90, and nct1008.
>
> Yes, and probably also board files as well.  Or either just accept
> bisection trouble for now or wait till the better stubbing is in there -

Ah, that is exactly the trouble I wanted to avoid.

> that will mean that for DT systems the core will just assume the supply
> is really there and not fail requests if it's not in the DT.
>
>>> The names requested by a driver are defined with regard to the device
>>> and should be the names used by the chip itself as defined in the
>
>> 9 votes for vdd, 11 votes for vcc, one undecided (no datasheet available).
>> Guess one is as good as the other ;-).
>
> What I've suggested before is to use the name from the part for which
> the driver is named.  Assuming the vendor doesn't randomly change their
> datasheet (but that causes problems for hardware engineers so tends to
> be avoided).
>
Makes sense.

Guenter
Wei Ni Aug. 9, 2013, 7:23 a.m. UTC | #23
On 08/08/2013 07:01 PM, Mark Brown wrote:
> * PGP Signed by an unknown key
> 
> On Thu, Aug 08, 2013 at 02:56:29PM +0800, Wei Ni wrote:
> 
>> +	mutex_lock(&data->update_lock);
>> +
>> +	if (is_enable)
>> +		ret = regulator_enable(data->lm90_reg);
>> +	else
>> +		ret = regulator_disable(data->lm90_reg);
>> +
>> +	if (ret < 0)
>> +		dev_err(&client->dev,
>> +			"Error in %s rail vdd, error %d\n",
>> +			(is_enable) ? "enabling" : "disabling", ret);
>> +	else
>> +		dev_info(&client->dev, "success in %s rail vdd\n",
>> +			 (is_enable) ? "enabling" : "disabling");
>> +
>> +	mutex_unlock(&data->update_lock);
> 
> Two things here.  One is that it's not clear what this lokc is
> protecting since the only thing in the locked region is the regulator
> operation and that is thread safe.  The other thing is that I'm not
> seeing anthing that ensures that enables and disables are matched -
> regulators are reference counted so two enables need two disables.
> 
>> +	data->lm90_reg = regulator_get(&client->dev, "vdd");
>> +	if (IS_ERR_OR_NULL(data->lm90_reg)) {
> 
> NULL is a valid regulator, use IS_ERR().
> 
>> +		if (PTR_ERR(data->lm90_reg) == -ENODEV)
>> +			dev_info(&client->dev,
>> +				 "No regulator found for vdd. Assuming vdd is always powered.");
>> +		else
>> +			dev_warn(&client->dev,
>> +				 "Error [%ld] in getting the regulator handle for vdd.\n",
>> +				 PTR_ERR(data->lm90_reg));
> 
> You shouldn't just be ignoring errors here, though there are deployment
> difficulties with making sure a stub regulator is provided.  These
> should be getting easier after the next merge window, the stubs will be
> being tweaked slightly to have an "assume it's there" option even when

Oh, really, could you show me the patch, I wish to take a look :)

Wei.

> regulators are used.  Especially in cases with device tree you should be
> paying attention to -EPROBE_DEFER, that will accurately reflect if a
> regulator is present but not loaded yet.
> 
> That said if you *are* going to do this you should request the
> regulator using devm_regulator_get_optional(), this is intended to
> support things that don't need regulators (though that's not the case
> here).
> 
> * Unknown Key
> * 0x7EA229BD
>
Mark Brown Aug. 9, 2013, 10:27 a.m. UTC | #24
On Fri, Aug 09, 2013 at 09:57:00AM +0400, Alexander Shiyan wrote:

> Instead of adding the support of regulators in each device, let's think about
> whether it is possible to create a global regulator for any device on the I2C bus.

> I see it like this:
> We add an extra field in the i2c_board_info structure "power_name" and handle
> it in the i2c_device_{probe/remove} functions.

This would need to be an array of supplies, relatively few devices need
only a single power supply.  This is also not something that should be
handled in I2C, power is not something that's uniquely needed by devices
on an I2C bus.

> The question remains how to maintain such regulator in the PM functions,
> but we can discuss it.

Well, there's some basic stuff for this for clocks already - a similar
pattern should work.  You need to use runtime PM to hook in the power
management and it's not going to work for everything (especially things
that can be wake sources) but there's some value in trying to factor out
the basic use case.
Alexander Shiyan Aug. 9, 2013, 10:50 a.m. UTC | #25
> On Fri, Aug 09, 2013 at 09:57:00AM +0400, Alexander Shiyan wrote:
> 
> > Instead of adding the support of regulators in each device, let's think about
> > whether it is possible to create a global regulator for any device on the I2C bus.
> 
> > I see it like this:
> > We add an extra field in the i2c_board_info structure "power_name" and handle
> > it in the i2c_device_{probe/remove} functions.
> 
> This would need to be an array of supplies, relatively few devices need
> only a single power supply.  This is also not something that should be
> handled in I2C, power is not something that's uniquely needed by devices
> on an I2C bus.

Additional regulators can be handled in the driver, or "parent"-scheme can
be used. Is not it?

---
Mark Brown Aug. 9, 2013, 10:56 a.m. UTC | #26
On Fri, Aug 09, 2013 at 03:23:31PM +0800, Wei Ni wrote:
> On 08/08/2013 07:01 PM, Mark Brown wrote:

> > You shouldn't just be ignoring errors here, though there are deployment
> > difficulties with making sure a stub regulator is provided.  These
> > should be getting easier after the next merge window, the stubs will be
> > being tweaked slightly to have an "assume it's there" option even when

> Oh, really, could you show me the patch, I wish to take a look :)

No patch quite yet - the basic idea is that for plain regulator_get()
you'll only ever get -EPROBE_DEFER as an error, not -ENODEV.  If the
regulator is missing in the DT we assume it's there and provide a dummy
if the DT doesn't hook it up.  If the consumer genuinely wants to see if
a supply might not be wired up it should use regulator_get_optional()
which is in -next at the minute.
Mark Brown Aug. 9, 2013, 11:09 a.m. UTC | #27
On Fri, Aug 09, 2013 at 02:50:11PM +0400, Alexander Shiyan wrote:

> > This would need to be an array of supplies, relatively few devices need
> > only a single power supply.  This is also not something that should be
> > handled in I2C, power is not something that's uniquely needed by devices
> > on an I2C bus.

> Additional regulators can be handled in the driver, or "parent"-scheme can
> be used. Is not it?

Given how common it is to have multiple supplies it seems sensible to
just handle that in the core - it's common to have a digital supply and
an analogue supply for example.  The regulator framework already has
APIs for working with multiple regulators in a single call so it's not
going to be much more effort on the framework side.
diff mbox

Patch

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index cdff742..306a348 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -89,6 +89,7 @@ 
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
 
 /*
  * Addresses to scan
@@ -302,6 +303,7 @@  static const struct lm90_params lm90_params[] = {
 struct lm90_data {
 	struct device *hwmon_dev;
 	struct mutex update_lock;
+	struct regulator *lm90_reg;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 	int kind;
@@ -1391,6 +1393,32 @@  static void lm90_init_client(struct i2c_client *client)
 		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
 }
 
+static void lm90_power_control(struct i2c_client *client, bool is_enable)
+{
+	struct lm90_data *data = i2c_get_clientdata(client);
+	int ret;
+
+	if (!data->lm90_reg)
+		return;
+
+	mutex_lock(&data->update_lock);
+
+	if (is_enable)
+		ret = regulator_enable(data->lm90_reg);
+	else
+		ret = regulator_disable(data->lm90_reg);
+
+	if (ret < 0)
+		dev_err(&client->dev,
+			"Error in %s rail vdd, error %d\n",
+			(is_enable) ? "enabling" : "disabling", ret);
+	else
+		dev_info(&client->dev, "success in %s rail vdd\n",
+			 (is_enable) ? "enabling" : "disabling");
+
+	mutex_unlock(&data->update_lock);
+}
+
 static int lm90_probe(struct i2c_client *client,
 		      const struct i2c_device_id *id)
 {
@@ -1406,6 +1434,20 @@  static int lm90_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
 
+	data->lm90_reg = regulator_get(&client->dev, "vdd");
+	if (IS_ERR_OR_NULL(data->lm90_reg)) {
+		if (PTR_ERR(data->lm90_reg) == -ENODEV)
+			dev_info(&client->dev,
+				 "No regulator found for vdd. Assuming vdd is always powered.");
+		else
+			dev_warn(&client->dev,
+				 "Error [%ld] in getting the regulator handle for vdd.\n",
+				 PTR_ERR(data->lm90_reg));
+		data->lm90_reg = NULL;
+	}
+
+	lm90_power_control(client, true);
+
 	/* Set the device type */
 	data->kind = id->driver_data;
 	if (data->kind == adm1032) {
@@ -1473,6 +1515,10 @@  exit_remove_files:
 	lm90_remove_files(client, data);
 exit_restore:
 	lm90_restore_conf(client, data);
+	lm90_power_control(client, false);
+	if (data->lm90_reg)
+		regulator_put(data->lm90_reg);
+
 	return err;
 }
 
@@ -1483,6 +1529,9 @@  static int lm90_remove(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	lm90_remove_files(client, data);
 	lm90_restore_conf(client, data);
+	lm90_power_control(client, false);
+	if (data->lm90_reg)
+		regulator_put(data->lm90_reg);
 
 	return 0;
 }