@@ -31,6 +31,8 @@ struct pwm_fan_ctx {
atomic_t pulses;
unsigned int rpm;
u8 pulses_per_revolution;
+ struct sensor_device_attribute sensor_attr;
+
ktime_t sample_start;
struct timer_list rpm_timer;
@@ -39,6 +41,9 @@ struct pwm_fan_ctx {
unsigned int pwm_fan_max_state;
unsigned int *pwm_fan_cooling_levels;
struct thermal_cooling_device *cdev;
+
+ struct attribute_group fan_group;
+ struct attribute_group *fan_groups[2];
};
/* This handler assumes self resetting edge triggered interrupt. */
@@ -138,36 +143,6 @@ static ssize_t rpm_show(struct device *dev,
}
static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
-static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0);
-
-static struct attribute *pwm_fan_attrs[] = {
- &sensor_dev_attr_pwm1.dev_attr.attr,
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- NULL,
-};
-
-static umode_t pwm_fan_attrs_visible(struct kobject *kobj, struct attribute *a,
- int n)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
-
- /* Hide fan_input in case no interrupt is available */
- if (n == 1 && ctx->irq <= 0)
- return 0;
-
- return a->mode;
-}
-
-static const struct attribute_group pwm_fan_group = {
- .attrs = pwm_fan_attrs,
- .is_visible = pwm_fan_attrs_visible,
-};
-
-static const struct attribute_group *pwm_fan_groups[] = {
- &pwm_fan_group,
- NULL,
-};
/* thermal cooling device callbacks */
static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
@@ -287,6 +262,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
int ret;
struct pwm_state state = { };
int tach_count;
+ size_t sz;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -340,6 +316,13 @@ static int pwm_fan_probe(struct platform_device *pdev)
return dev_err_probe(dev, tach_count,
"Could not get number of fan tachometer inputs\n");
+ sz = (2 + tach_count) * sizeof(struct attribute *);
+ ctx->fan_group.attrs = devm_kzalloc(dev, sz, GFP_KERNEL);
+ if (!ctx->fan_group.attrs)
+ return -ENOMEM;
+
+ ctx->fan_group.attrs[0] = &sensor_dev_attr_pwm1.dev_attr.attr;
+
if (tach_count > 0) {
u32 ppr = 2;
@@ -366,6 +349,13 @@ static int pwm_fan_probe(struct platform_device *pdev)
return -EINVAL;
}
+ sysfs_attr_init(&ctx->sensor_attr.dev_attr.attr);
+
+ ctx->sensor_attr.dev_attr.attr.name = "fan1_input";
+ ctx->sensor_attr.dev_attr.attr.mode = 0444;
+ ctx->sensor_attr.dev_attr.show = rpm_show;
+ ctx->fan_group.attrs[1] = &ctx->sensor_attr.dev_attr.attr;
+
dev_dbg(dev, "tach: irq=%d, pulses_per_revolution=%d\n",
ctx->irq, ctx->pulses_per_revolution);
@@ -373,8 +363,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
mod_timer(&ctx->rpm_timer, jiffies + HZ);
}
- hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan",
- ctx, pwm_fan_groups);
+ ctx->fan_groups[0] = &ctx->fan_group;
+ hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan", ctx,
+ (const struct attribute_group **)ctx->fan_groups);
if (IS_ERR(hwmon)) {
dev_err(dev, "Failed to register hwmon device\n");
return PTR_ERR(hwmon);
Instead of implementing an is_visible function we can dynamically populate the attribute group for the device based on whether a fan tachometer input is configured or not. Signed-off-by: Paul Barker <pbarker@konsulko.com> --- drivers/hwmon/pwm-fan.c | 55 +++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 32 deletions(-)