RE: [PATCH v3] pwm: add sysfs interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Monday, June 10, 2013 12:00 PM, Thierry Reding wrote:
> On Thu, May 30, 2013 at 02:30:39PM -0700, H Hartley Sweeten wrote:
>> Add a simple sysfs interface to the generic PWM framework.
>
> Sorry for taking so long to review this.

Not a problem. Thanks for the review.

>>   /sys/class/pwm/
>>   `-- pwmchipN/          for each PWM chip
>>       |-- export         (w/o) ask the kernel to export a PWM channel
>>       |-- npwn           (r/o) number of PWM channels in this PWM chip
>
> "npwm"?

Fat-fingered that. Fixed.

>>       |-- pwmX/          for each exported PWM channel
>>       |   |-- duty_ns    (r/w) duty cycle (in nanoseconds)
>>       |   |-- enable     (r/w) enable/disable PWM
>>       |   |-- period_ns  (r/w) period (in nanoseconds)
>
> I'm not sure if we need the _ns suffix. If the documentation already
> specifies that it should be in nanoseconds, shouldn't that be enough?

In the earlier review of Lars Poeschel's patch I think you said you wanted the
attributes to match the variable names.

But, "duty' and "period" are probably close enough. Fixed.

>> diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
> [...]
>> +What:		/sys/class/pwm/pwmchipN/pwmX/polarity
>> +Date:		May 2013
>> +KernelVersion:	3.11
>> +Contact:	H Hartley Sweeten <hsweeten@xxxxxxxxxxxxxxxxxxx>
>> +Description:
>> +		Sets the output polarity of the PWM.
>> +		0 is normal polarity
>> +		1 is inversed polarity
>
>I think this was discussed before, and I think it makes sense to use the
>string representation here. polarity = 0 or polarity = 1 aren't very
>intuitive notations in my opinion.

You did mention that before. I overlooked it.

I'll change this.

>> diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
> [...]
>> +The PWM channels are PWM chip specific from 0 to npwn-1.
>
>"npwm-1". "channels are PWM chip specific" sounds a bit confusing. Maybe
>something like "The PWM channels are numbered using a per-chip index
>from 0 to npwm-1." is more precise?

Ok.

>> +When a PWM channel is exported a pwmX directory will be created in the
>> +pwmchipN directory it is associated with, where X is the channel number
>> +that was exported.
>
>"..., where X is the number of the channel that was exported."?

Ok.

>> The following properties will then be available:
>> +
>> +period_ns - The total period of the PWM (read/write).
>
> "PWM signal"?

OK.

>> +	Value is in nanoseconds and is the sum of the active and inactive
>> +	time of the PWM. If duty_ns is zero when this property is written
>> +	it will be automatically set to half the period_ns.
>
> I'm not sure that's the best approach. How about deferring the PWM
> configuration until both values have been set? Or only configure the PWM
> channel when it has been enabled, and refuse to enable unless both the
> period and the duty cycle have been set?

See below.

>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>> index 94ba21e..fb92e1d 100644
>> --- a/drivers/pwm/Makefile
>> +++ b/drivers/pwm/Makefile
>> @@ -1,4 +1,5 @@
>>  obj-$(CONFIG_PWM)		+= core.o
>> +obj-$(CONFIG_PWM_SYSFS)		+= pwm-sysfs.o
>
> I'd prefer this to simple be named sysfs.[co] in order to differentiate
> it from drivers and make it consistent with the naming of core.[co].

Ok.

>> diff --git a/drivers/pwm/pwm-sysfs.c b/drivers/pwm/pwm-sysfs.c
> [...]
>> +static struct pwm_device *dev_to_pwm_device(struct device *dev)
>> +{
>> +	struct pwm_export *pwm_export = dev_to_pwm_export(dev);
>
> Maybe drop the pwm_ prefix on the variable name?

Ok.

>> +static ssize_t pwm_period_ns_store(struct device *dev,
>> +				   struct device_attribute *attr,
>> +				   const char *buf, size_t size)
>> +{
>> +	struct pwm_device *pwm = dev_to_pwm_device(dev);
>> +	unsigned int duty = pwm->duty;
>> +	unsigned int val;
>> +	int ret;
>> +
>> +	ret = kstrtouint(buf, 0, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* if not set, default to 50% duty cycle */
>> +	if (duty == 0)
>> +		duty = val / 2;
>
> How does this differentiate between the case where the user explicitly
> sets the duty cycle to 0 to "disable" the PWM?

It doesn't.

Actually, looking at pwm_config() a duty_ns value of 0 is allowed so this
check is not necessary.


>> +static ssize_t pwm_enable_store(struct device *dev,
>> +				struct device_attribute *attr,
>> +				const char *buf, size_t size)
>> +{
>> +	struct pwm_device *pwm = dev_to_pwm_device(dev);
>> +	int val;
>> +	int ret;
>
> These could go on one line.

Nitpick... Ok.

>> +
>> +	ret = kstrtoint(buf, 0, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	switch (val) {
>> +	case 0:
>> +		pwm_disable(pwm);
>> +		ret = 0;
>
> I don't think ret can be anything other than 0 given the above validity
> check.

Ok.

>> +static ssize_t pwm_polarity_show(struct device *dev,
>> +				 struct device_attribute *attr,
>> +				 char *buf)
>> +{
>> +	const struct pwm_device *pwm = dev_to_pwm_device(dev);
>> +
>> +	return sprintf(buf, "%d\n", pwm->polarity);
>> +}
>> +
>> +static ssize_t pwm_polarity_store(struct device *dev,
>> +				  struct device_attribute *attr,
>> +				  const char *buf, size_t size)
>> +{
>> +	struct pwm_device *pwm = dev_to_pwm_device(dev);
>> +	enum pwm_polarity polarity;
>> +	int val;
>> +	int ret;
>
> Could go on a single line.

Ok.

>> +
>> +	ret = kstrtoint(buf, 0, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	switch (val) {
>> +	case 0:
>> +		polarity = PWM_POLARITY_NORMAL;
>> +		break;
>> +	case 1:
>> +		polarity = PWM_POLARITY_INVERSED;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = pwm_set_polarity(pwm, polarity);
>> +
>> +	return ret ? : size;
>> +}
>> +
>> +static DEVICE_ATTR(period_ns, 0644, pwm_period_ns_show, pwm_period_ns_store);
>> +static DEVICE_ATTR(duty_ns, 0644, pwm_duty_ns_show, pwm_duty_ns_store);
>> +static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
>> +static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
>> +
>> +static struct attribute *pwm_attrs[] = {
>> +	&dev_attr_period_ns.attr,
>> +	&dev_attr_duty_ns.attr,
>> +	&dev_attr_enable.attr,
>> +	&dev_attr_polarity.attr,
>> +	NULL
>> +};
>> +
>> +static struct attribute_group pwm_attr_group = {
>> +	.attrs		= pwm_attrs,
>> +};
>
> static const?

Ok.

>> +static void pwm_export_release(struct device *dev)
>> +{
>> +	struct pwm_export *pwm_export = dev_to_pwm_export(dev);
>> +
>> +	kfree(pwm_export);
>> +}
>
> Again, the pwm_ prefix for the variable name seems gratuitous here.

Ok.

>> +
>> +static int pwm_export(struct device *dev, struct pwm_device *pwm)
>> +{
>> +	struct pwm_export *pwm_export;
>
> And here as well.

Ok.

>> +static int pwm_unexport_match(struct device *dev, void *data)
>> +{
>> +	return dev_to_pwm_device(dev) == data;
>> +}
>> +
>> +static int pwm_unexport(struct device *dev, struct pwm_device *pwm)
>
> I think the current naming of variables is very confusing. It's hard to
> keep track of what's what. Maybe dev --> parent, or dev --> chip?
> Then...
>
>> +{
>> +	struct device *export_dev;
>
> export_dev --> dev, and...
>
>> +	struct pwm_export *pwm_export;
>
> pwm_export --> export?

I'll work out a clearer naming for the variables.

>> +
>> +	if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
>> +		return -ENODEV;
>> +
>> +	export_dev = device_find_child(dev, pwm, pwm_unexport_match);
>> +	pwm_export = dev_to_pwm_export(export_dev);
>> +	put_device(&pwm_export->dev);
>> +	device_unregister(&pwm_export->dev);
>
> device_unregister() already calls put_device(), why do you do it again
> here?

device_find_child() does a get_device().

>> +	pwm_put(pwm);
>> +
>> +	return 0;
>> +}
>> +
>
> [...]
>> +void pwmchip_sysfs_export(struct pwm_chip *chip)
>> +{
>> +	/*
>> +	 * If device_create() fails the pwm_chip is still usable by
>> +	 * the kernel its just not exported.
>> +	 */
>> +	device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
>> +		      "pwmchip%d", chip->base);
>> +}
>
> Maybe a warning message would still be useful in that case?

OK.

>> +void pwmchip_sysfs_unexport(struct pwm_chip *chip)
>> +{
>> +	struct device *dev;
>> +
>> +	dev = class_find_device(&pwm_class, NULL, chip, pwmchip_sysfs_match);
>> +	if (dev) {
>> +		put_device(dev);
>> +		device_unregister(dev);
>
>device_unregister() already calls put_device(), why do you do it again
> here?

class_find_device() does a get_device().

>> diff --git a/include/linux/pwm.h b/include/linux/pwm.h
> [...]
>> +	unsigned int		duty;	/* in nanoseconds */
>
> I'd prefer this to be called duty_cycle.

Ok.

I'll clean this all up and post a v4 later.

Thanks,
Hartley

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux