linux/drivers/pwm/sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * A simple sysfs interface for the generic PWM framework
   4 *
   5 * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
   6 *
   7 * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
   8 */
   9
  10#include <linux/device.h>
  11#include <linux/mutex.h>
  12#include <linux/err.h>
  13#include <linux/slab.h>
  14#include <linux/kdev_t.h>
  15#include <linux/pwm.h>
  16
  17struct pwm_export {
  18        struct device child;
  19        struct pwm_device *pwm;
  20        struct mutex lock;
  21};
  22
  23static struct pwm_export *child_to_pwm_export(struct device *child)
  24{
  25        return container_of(child, struct pwm_export, child);
  26}
  27
  28static struct pwm_device *child_to_pwm_device(struct device *child)
  29{
  30        struct pwm_export *export = child_to_pwm_export(child);
  31
  32        return export->pwm;
  33}
  34
  35static ssize_t period_show(struct device *child,
  36                           struct device_attribute *attr,
  37                           char *buf)
  38{
  39        const struct pwm_device *pwm = child_to_pwm_device(child);
  40        struct pwm_state state;
  41
  42        pwm_get_state(pwm, &state);
  43
  44        return sprintf(buf, "%u\n", state.period);
  45}
  46
  47static ssize_t period_store(struct device *child,
  48                            struct device_attribute *attr,
  49                            const char *buf, size_t size)
  50{
  51        struct pwm_export *export = child_to_pwm_export(child);
  52        struct pwm_device *pwm = export->pwm;
  53        struct pwm_state state;
  54        unsigned int val;
  55        int ret;
  56
  57        ret = kstrtouint(buf, 0, &val);
  58        if (ret)
  59                return ret;
  60
  61        mutex_lock(&export->lock);
  62        pwm_get_state(pwm, &state);
  63        state.period = val;
  64        ret = pwm_apply_state(pwm, &state);
  65        mutex_unlock(&export->lock);
  66
  67        return ret ? : size;
  68}
  69
  70static ssize_t duty_cycle_show(struct device *child,
  71                               struct device_attribute *attr,
  72                               char *buf)
  73{
  74        const struct pwm_device *pwm = child_to_pwm_device(child);
  75        struct pwm_state state;
  76
  77        pwm_get_state(pwm, &state);
  78
  79        return sprintf(buf, "%u\n", state.duty_cycle);
  80}
  81
  82static ssize_t duty_cycle_store(struct device *child,
  83                                struct device_attribute *attr,
  84                                const char *buf, size_t size)
  85{
  86        struct pwm_export *export = child_to_pwm_export(child);
  87        struct pwm_device *pwm = export->pwm;
  88        struct pwm_state state;
  89        unsigned int val;
  90        int ret;
  91
  92        ret = kstrtouint(buf, 0, &val);
  93        if (ret)
  94                return ret;
  95
  96        mutex_lock(&export->lock);
  97        pwm_get_state(pwm, &state);
  98        state.duty_cycle = val;
  99        ret = pwm_apply_state(pwm, &state);
 100        mutex_unlock(&export->lock);
 101
 102        return ret ? : size;
 103}
 104
 105static ssize_t enable_show(struct device *child,
 106                           struct device_attribute *attr,
 107                           char *buf)
 108{
 109        const struct pwm_device *pwm = child_to_pwm_device(child);
 110        struct pwm_state state;
 111
 112        pwm_get_state(pwm, &state);
 113
 114        return sprintf(buf, "%d\n", state.enabled);
 115}
 116
 117static ssize_t enable_store(struct device *child,
 118                            struct device_attribute *attr,
 119                            const char *buf, size_t size)
 120{
 121        struct pwm_export *export = child_to_pwm_export(child);
 122        struct pwm_device *pwm = export->pwm;
 123        struct pwm_state state;
 124        int val, ret;
 125
 126        ret = kstrtoint(buf, 0, &val);
 127        if (ret)
 128                return ret;
 129
 130        mutex_lock(&export->lock);
 131
 132        pwm_get_state(pwm, &state);
 133
 134        switch (val) {
 135        case 0:
 136                state.enabled = false;
 137                break;
 138        case 1:
 139                state.enabled = true;
 140                break;
 141        default:
 142                ret = -EINVAL;
 143                goto unlock;
 144        }
 145
 146        ret = pwm_apply_state(pwm, &state);
 147
 148unlock:
 149        mutex_unlock(&export->lock);
 150        return ret ? : size;
 151}
 152
 153static ssize_t polarity_show(struct device *child,
 154                             struct device_attribute *attr,
 155                             char *buf)
 156{
 157        const struct pwm_device *pwm = child_to_pwm_device(child);
 158        const char *polarity = "unknown";
 159        struct pwm_state state;
 160
 161        pwm_get_state(pwm, &state);
 162
 163        switch (state.polarity) {
 164        case PWM_POLARITY_NORMAL:
 165                polarity = "normal";
 166                break;
 167
 168        case PWM_POLARITY_INVERSED:
 169                polarity = "inversed";
 170                break;
 171        }
 172
 173        return sprintf(buf, "%s\n", polarity);
 174}
 175
 176static ssize_t polarity_store(struct device *child,
 177                              struct device_attribute *attr,
 178                              const char *buf, size_t size)
 179{
 180        struct pwm_export *export = child_to_pwm_export(child);
 181        struct pwm_device *pwm = export->pwm;
 182        enum pwm_polarity polarity;
 183        struct pwm_state state;
 184        int ret;
 185
 186        if (sysfs_streq(buf, "normal"))
 187                polarity = PWM_POLARITY_NORMAL;
 188        else if (sysfs_streq(buf, "inversed"))
 189                polarity = PWM_POLARITY_INVERSED;
 190        else
 191                return -EINVAL;
 192
 193        mutex_lock(&export->lock);
 194        pwm_get_state(pwm, &state);
 195        state.polarity = polarity;
 196        ret = pwm_apply_state(pwm, &state);
 197        mutex_unlock(&export->lock);
 198
 199        return ret ? : size;
 200}
 201
 202static ssize_t capture_show(struct device *child,
 203                            struct device_attribute *attr,
 204                            char *buf)
 205{
 206        struct pwm_device *pwm = child_to_pwm_device(child);
 207        struct pwm_capture result;
 208        int ret;
 209
 210        ret = pwm_capture(pwm, &result, jiffies_to_msecs(HZ));
 211        if (ret)
 212                return ret;
 213
 214        return sprintf(buf, "%u %u\n", result.period, result.duty_cycle);
 215}
 216
 217static DEVICE_ATTR_RW(period);
 218static DEVICE_ATTR_RW(duty_cycle);
 219static DEVICE_ATTR_RW(enable);
 220static DEVICE_ATTR_RW(polarity);
 221static DEVICE_ATTR_RO(capture);
 222
 223static struct attribute *pwm_attrs[] = {
 224        &dev_attr_period.attr,
 225        &dev_attr_duty_cycle.attr,
 226        &dev_attr_enable.attr,
 227        &dev_attr_polarity.attr,
 228        &dev_attr_capture.attr,
 229        NULL
 230};
 231ATTRIBUTE_GROUPS(pwm);
 232
 233static void pwm_export_release(struct device *child)
 234{
 235        struct pwm_export *export = child_to_pwm_export(child);
 236
 237        kfree(export);
 238}
 239
 240static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
 241{
 242        struct pwm_export *export;
 243        char *pwm_prop[2];
 244        int ret;
 245
 246        if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
 247                return -EBUSY;
 248
 249        export = kzalloc(sizeof(*export), GFP_KERNEL);
 250        if (!export) {
 251                clear_bit(PWMF_EXPORTED, &pwm->flags);
 252                return -ENOMEM;
 253        }
 254
 255        export->pwm = pwm;
 256        mutex_init(&export->lock);
 257
 258        export->child.release = pwm_export_release;
 259        export->child.parent = parent;
 260        export->child.devt = MKDEV(0, 0);
 261        export->child.groups = pwm_groups;
 262        dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
 263
 264        ret = device_register(&export->child);
 265        if (ret) {
 266                clear_bit(PWMF_EXPORTED, &pwm->flags);
 267                put_device(&export->child);
 268                export = NULL;
 269                return ret;
 270        }
 271        pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm);
 272        pwm_prop[1] = NULL;
 273        kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
 274        kfree(pwm_prop[0]);
 275
 276        return 0;
 277}
 278
 279static int pwm_unexport_match(struct device *child, void *data)
 280{
 281        return child_to_pwm_device(child) == data;
 282}
 283
 284static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
 285{
 286        struct device *child;
 287        char *pwm_prop[2];
 288
 289        if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
 290                return -ENODEV;
 291
 292        child = device_find_child(parent, pwm, pwm_unexport_match);
 293        if (!child)
 294                return -ENODEV;
 295
 296        pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm);
 297        pwm_prop[1] = NULL;
 298        kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
 299        kfree(pwm_prop[0]);
 300
 301        /* for device_find_child() */
 302        put_device(child);
 303        device_unregister(child);
 304        pwm_put(pwm);
 305
 306        return 0;
 307}
 308
 309static ssize_t export_store(struct device *parent,
 310                            struct device_attribute *attr,
 311                            const char *buf, size_t len)
 312{
 313        struct pwm_chip *chip = dev_get_drvdata(parent);
 314        struct pwm_device *pwm;
 315        unsigned int hwpwm;
 316        int ret;
 317
 318        ret = kstrtouint(buf, 0, &hwpwm);
 319        if (ret < 0)
 320                return ret;
 321
 322        if (hwpwm >= chip->npwm)
 323                return -ENODEV;
 324
 325        pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
 326        if (IS_ERR(pwm))
 327                return PTR_ERR(pwm);
 328
 329        ret = pwm_export_child(parent, pwm);
 330        if (ret < 0)
 331                pwm_put(pwm);
 332
 333        return ret ? : len;
 334}
 335static DEVICE_ATTR_WO(export);
 336
 337static ssize_t unexport_store(struct device *parent,
 338                              struct device_attribute *attr,
 339                              const char *buf, size_t len)
 340{
 341        struct pwm_chip *chip = dev_get_drvdata(parent);
 342        unsigned int hwpwm;
 343        int ret;
 344
 345        ret = kstrtouint(buf, 0, &hwpwm);
 346        if (ret < 0)
 347                return ret;
 348
 349        if (hwpwm >= chip->npwm)
 350                return -ENODEV;
 351
 352        ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
 353
 354        return ret ? : len;
 355}
 356static DEVICE_ATTR_WO(unexport);
 357
 358static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
 359                         char *buf)
 360{
 361        const struct pwm_chip *chip = dev_get_drvdata(parent);
 362
 363        return sprintf(buf, "%u\n", chip->npwm);
 364}
 365static DEVICE_ATTR_RO(npwm);
 366
 367static struct attribute *pwm_chip_attrs[] = {
 368        &dev_attr_export.attr,
 369        &dev_attr_unexport.attr,
 370        &dev_attr_npwm.attr,
 371        NULL,
 372};
 373ATTRIBUTE_GROUPS(pwm_chip);
 374
 375static struct class pwm_class = {
 376        .name = "pwm",
 377        .owner = THIS_MODULE,
 378        .dev_groups = pwm_chip_groups,
 379};
 380
 381static int pwmchip_sysfs_match(struct device *parent, const void *data)
 382{
 383        return dev_get_drvdata(parent) == data;
 384}
 385
 386void pwmchip_sysfs_export(struct pwm_chip *chip)
 387{
 388        struct device *parent;
 389
 390        /*
 391         * If device_create() fails the pwm_chip is still usable by
 392         * the kernel it's just not exported.
 393         */
 394        parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
 395                               "pwmchip%d", chip->base);
 396        if (IS_ERR(parent)) {
 397                dev_warn(chip->dev,
 398                         "device_create failed for pwm_chip sysfs export\n");
 399        }
 400}
 401
 402void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 403{
 404        struct device *parent;
 405        unsigned int i;
 406
 407        parent = class_find_device(&pwm_class, NULL, chip,
 408                                   pwmchip_sysfs_match);
 409        if (!parent)
 410                return;
 411
 412        for (i = 0; i < chip->npwm; i++) {
 413                struct pwm_device *pwm = &chip->pwms[i];
 414
 415                if (test_bit(PWMF_EXPORTED, &pwm->flags))
 416                        pwm_unexport_child(parent, pwm);
 417        }
 418
 419        put_device(parent);
 420        device_unregister(parent);
 421}
 422
 423static int __init pwm_sysfs_init(void)
 424{
 425        return class_register(&pwm_class);
 426}
 427subsys_initcall(pwm_sysfs_init);
 428