/* * If the alarm GPIO don't support interrupts, just leave * without initializing the fail notification support.
*/
alarm_irq = gpiod_to_irq(fan_data->alarm_gpio); if (alarm_irq <= 0) return 0;
/* Must be called with fan_data->lock held, except during initialization. */ staticvoid __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
{ int i;
for (i = 0; i < fan_data->num_gpios; i++)
gpiod_set_value_cansleep(fan_data->gpios[i],
(ctrl_val >> i) & 1);
}
staticint __get_fan_ctrl(struct gpio_fan_data *fan_data)
{ int i; int ctrl_val = 0;
for (i = 0; i < fan_data->num_gpios; i++) { int value;
/* Must be called with fan_data->lock held, except during initialization. */ staticint set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
{ if (fan_data->speed_index == speed_index) return 0;
if (fan_data->speed_index == 0 && speed_index > 0) { int ret;
ret = pm_runtime_resume_and_get(fan_data->dev); if (ret < 0) return ret;
}
staticint fan_ctrl_init(struct gpio_fan_data *fan_data)
{ int num_gpios = fan_data->num_gpios; struct gpio_desc **gpios = fan_data->gpios; int i, err;
for (i = 0; i < num_gpios; i++) { /* * The GPIO descriptors were retrieved with GPIOD_ASIS so here * we set the GPIO into output mode, carefully preserving the * current value by setting it to whatever it is already set * (no surprise changes in default fan speed).
*/
err = gpiod_direction_output(gpios[i],
gpiod_get_value_cansleep(gpios[i])); if (err) return err;
}
fan_data->pwm_enable = true; /* Enable manual fan speed control. */
fan_data->speed_index = get_fan_speed_index(fan_data); if (fan_data->speed_index < 0) return fan_data->speed_index;
/* Alarm GPIO if one exists */
fan_data->alarm_gpio = devm_gpiod_get_optional(dev, "alarm", GPIOD_IN); if (IS_ERR(fan_data->alarm_gpio)) return PTR_ERR(fan_data->alarm_gpio);
/* Fill GPIO pin array */
fan_data->num_gpios = gpiod_count(dev, NULL); if (fan_data->num_gpios <= 0) { if (fan_data->alarm_gpio) return 0;
dev_err(dev, "DT properties empty / missing"); return -ENODEV;
}
gpios = devm_kcalloc(dev,
fan_data->num_gpios, sizeof(struct gpio_desc *),
GFP_KERNEL); if (!gpios) return -ENOMEM; for (i = 0; i < fan_data->num_gpios; i++) {
gpios[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS); if (IS_ERR(gpios[i])) return PTR_ERR(gpios[i]);
}
fan_data->gpios = gpios;
/* Get number of RPM/ctrl_val pairs in speed map */
prop = of_find_property(np, "gpio-fan,speed-map", &i); if (!prop) {
dev_err(dev, "gpio-fan,speed-map DT property missing"); return -ENODEV;
}
i = i / sizeof(u32); if (i == 0 || i & 1) {
dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries"); return -ENODEV;
}
fan_data->num_speed = i / 2;
/* * Populate speed map * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...> * this needs splitting into pairs to create gpio_fan_speed structs
*/
speed = devm_kcalloc(dev,
fan_data->num_speed, sizeof(struct gpio_fan_speed),
GFP_KERNEL); if (!speed) return -ENOMEM;
p = NULL; for (i = 0; i < fan_data->num_speed; i++) {
p = of_prop_next_u32(prop, p, &u); if (!p) return -ENODEV;
speed[i].rpm = u;
p = of_prop_next_u32(prop, p, &u); if (!p) return -ENODEV;
speed[i].ctrl_val = u;
}
fan_data->speed = speed;
fan_data->supply = devm_regulator_get(dev, "fan"); if (IS_ERR(fan_data->supply)) return dev_err_probe(dev, PTR_ERR(fan_data->supply), "Failed to get fan-supply");
/* Configure control GPIOs if available. */ if (fan_data->gpios && fan_data->num_gpios > 0) { if (!fan_data->speed || fan_data->num_speed <= 1) return -EINVAL;
err = fan_ctrl_init(fan_data); if (err) return err;
err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data); if (err) return err;
}
/* Make this driver part of hwmon class. */
fan_data->hwmon_dev =
devm_hwmon_device_register_with_groups(dev, "gpio_fan", fan_data,
gpio_fan_groups); if (IS_ERR(fan_data->hwmon_dev)) return PTR_ERR(fan_data->hwmon_dev);
/* Configure alarm GPIO if available. */ if (fan_data->alarm_gpio) {
err = fan_alarm_init(fan_data); if (err) return err;
}
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_enable(&pdev->dev); /* If current GPIO state is active, mark RPM as active as well */ if (fan_data->speed_index > 0) { int ret;
ret = pm_runtime_resume_and_get(&pdev->dev); if (ret) return ret;
}
/* Optional cooling device register for Device tree platforms */
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np, "gpio-fan", fan_data, &gpio_fan_cool_ops);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.