linux/drivers/pwm/sysfs.c
<<
>>
Prefs
   1/*
   2 * A simple sysfs interface for the generic PWM framework
   3 *
   4 * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
   5 *
   6 * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2, or (at your option)
  11 * any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/device.h>
  20#include <linux/mutex.h>
  21#include <linux/err.h>
  22#include <linux/slab.h>
  23#include <linux/kdev_t.h>
  24#include <linux/pwm.h>
  25
  26struct pwm_export {
  27        struct device child;
  28        struct pwm_device *pwm;
  29};
  30
  31static struct pwm_export *child_to_pwm_export(struct device *child)
  32{
  33        return container_of(child, struct pwm_export, child);
  34}
  35
  36static struct pwm_device *child_to_pwm_device(struct device *child)
  37{
  38        struct pwm_export *export = child_to_pwm_export(child);
  39
  40        return export->pwm;
  41}
  42
  43static ssize_t period_show(struct device *child,
  44                           struct device_attribute *attr,
  45                           char *buf)
  46{
  47        const struct pwm_device *pwm = child_to_pwm_device(child);
  48
  49        return sprintf(buf, "%u\n", pwm_get_period(pwm));
  50}
  51
  52static ssize_t period_store(struct device *child,
  53                            struct device_attribute *attr,
  54                            const char *buf, size_t size)
  55{
  56        struct pwm_device *pwm = child_to_pwm_device(child);
  57        unsigned int val;
  58        int ret;
  59
  60        ret = kstrtouint(buf, 0, &val);
  61        if (ret)
  62                return ret;
  63
  64        ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val);
  65
  66        return ret ? : size;
  67}
  68
  69static ssize_t duty_cycle_show(struct device *child,
  70                               struct device_attribute *attr,
  71                               char *buf)
  72{
  73        const struct pwm_device *pwm = child_to_pwm_device(child);
  74
  75        return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
  76}
  77
  78static ssize_t duty_cycle_store(struct device *child,
  79                                struct device_attribute *attr,
  80                                const char *buf, size_t size)
  81{
  82        struct pwm_device *pwm = child_to_pwm_device(child);
  83        unsigned int val;
  84        int ret;
  85
  86        ret = kstrtouint(buf, 0, &val);
  87        if (ret)
  88                return ret;
  89
  90        ret = pwm_config(pwm, val, pwm_get_period(pwm));
  91
  92        return ret ? : size;
  93}
  94
  95static ssize_t enable_show(struct device *child,
  96                           struct device_attribute *attr,
  97                           char *buf)
  98{
  99        const struct pwm_device *pwm = child_to_pwm_device(child);
 100
 101        return sprintf(buf, "%d\n", pwm_is_enabled(pwm));
 102}
 103
 104static ssize_t enable_store(struct device *child,
 105                            struct device_attribute *attr,
 106                            const char *buf, size_t size)
 107{
 108        struct pwm_device *pwm = child_to_pwm_device(child);
 109        int val, ret;
 110
 111        ret = kstrtoint(buf, 0, &val);
 112        if (ret)
 113                return ret;
 114
 115        switch (val) {
 116        case 0:
 117                pwm_disable(pwm);
 118                break;
 119        case 1:
 120                ret = pwm_enable(pwm);
 121                break;
 122        default:
 123                ret = -EINVAL;
 124                break;
 125        }
 126
 127        return ret ? : size;
 128}
 129
 130static ssize_t polarity_show(struct device *child,
 131                             struct device_attribute *attr,
 132                             char *buf)
 133{
 134        const struct pwm_device *pwm = child_to_pwm_device(child);
 135        const char *polarity = "unknown";
 136
 137        switch (pwm_get_polarity(pwm)) {
 138        case PWM_POLARITY_NORMAL:
 139                polarity = "normal";
 140                break;
 141
 142        case PWM_POLARITY_INVERSED:
 143                polarity = "inversed";
 144                break;
 145        }
 146
 147        return sprintf(buf, "%s\n", polarity);
 148}
 149
 150static ssize_t polarity_store(struct device *child,
 151                              struct device_attribute *attr,
 152                              const char *buf, size_t size)
 153{
 154        struct pwm_device *pwm = child_to_pwm_device(child);
 155        enum pwm_polarity polarity;
 156        int ret;
 157
 158        if (sysfs_streq(buf, "normal"))
 159                polarity = PWM_POLARITY_NORMAL;
 160        else if (sysfs_streq(buf, "inversed"))
 161                polarity = PWM_POLARITY_INVERSED;
 162        else
 163                return -EINVAL;
 164
 165        ret = pwm_set_polarity(pwm, polarity);
 166
 167        return ret ? : size;
 168}
 169
 170static DEVICE_ATTR_RW(period);
 171static DEVICE_ATTR_RW(duty_cycle);
 172static DEVICE_ATTR_RW(enable);
 173static DEVICE_ATTR_RW(polarity);
 174
 175static struct attribute *pwm_attrs[] = {
 176        &dev_attr_period.attr,
 177        &dev_attr_duty_cycle.attr,
 178        &dev_attr_enable.attr,
 179        &dev_attr_polarity.attr,
 180        NULL
 181};
 182ATTRIBUTE_GROUPS(pwm);
 183
 184static void pwm_export_release(struct device *child)
 185{
 186        struct pwm_export *export = child_to_pwm_export(child);
 187
 188        kfree(export);
 189}
 190
 191static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
 192{
 193        struct pwm_export *export;
 194        int ret;
 195
 196        if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
 197                return -EBUSY;
 198
 199        export = kzalloc(sizeof(*export), GFP_KERNEL);
 200        if (!export) {
 201                clear_bit(PWMF_EXPORTED, &pwm->flags);
 202                return -ENOMEM;
 203        }
 204
 205        export->pwm = pwm;
 206
 207        export->child.release = pwm_export_release;
 208        export->child.parent = parent;
 209        export->child.devt = MKDEV(0, 0);
 210        export->child.groups = pwm_groups;
 211        dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
 212
 213        ret = device_register(&export->child);
 214        if (ret) {
 215                clear_bit(PWMF_EXPORTED, &pwm->flags);
 216                kfree(export);
 217                return ret;
 218        }
 219
 220        return 0;
 221}
 222
 223static int pwm_unexport_match(struct device *child, void *data)
 224{
 225        return child_to_pwm_device(child) == data;
 226}
 227
 228static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
 229{
 230        struct device *child;
 231
 232        if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
 233                return -ENODEV;
 234
 235        child = device_find_child(parent, pwm, pwm_unexport_match);
 236        if (!child)
 237                return -ENODEV;
 238
 239        /* for device_find_child() */
 240        put_device(child);
 241        device_unregister(child);
 242        pwm_put(pwm);
 243
 244        return 0;
 245}
 246
 247static ssize_t export_store(struct device *parent,
 248                            struct device_attribute *attr,
 249                            const char *buf, size_t len)
 250{
 251        struct pwm_chip *chip = dev_get_drvdata(parent);
 252        struct pwm_device *pwm;
 253        unsigned int hwpwm;
 254        int ret;
 255
 256        ret = kstrtouint(buf, 0, &hwpwm);
 257        if (ret < 0)
 258                return ret;
 259
 260        if (hwpwm >= chip->npwm)
 261                return -ENODEV;
 262
 263        pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
 264        if (IS_ERR(pwm))
 265                return PTR_ERR(pwm);
 266
 267        ret = pwm_export_child(parent, pwm);
 268        if (ret < 0)
 269                pwm_put(pwm);
 270
 271        return ret ? : len;
 272}
 273static DEVICE_ATTR_WO(export);
 274
 275static ssize_t unexport_store(struct device *parent,
 276                              struct device_attribute *attr,
 277                              const char *buf, size_t len)
 278{
 279        struct pwm_chip *chip = dev_get_drvdata(parent);
 280        unsigned int hwpwm;
 281        int ret;
 282
 283        ret = kstrtouint(buf, 0, &hwpwm);
 284        if (ret < 0)
 285                return ret;
 286
 287        if (hwpwm >= chip->npwm)
 288                return -ENODEV;
 289
 290        ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
 291
 292        return ret ? : len;
 293}
 294static DEVICE_ATTR_WO(unexport);
 295
 296static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
 297                         char *buf)
 298{
 299        const struct pwm_chip *chip = dev_get_drvdata(parent);
 300
 301        return sprintf(buf, "%u\n", chip->npwm);
 302}
 303static DEVICE_ATTR_RO(npwm);
 304
 305static struct attribute *pwm_chip_attrs[] = {
 306        &dev_attr_export.attr,
 307        &dev_attr_unexport.attr,
 308        &dev_attr_npwm.attr,
 309        NULL,
 310};
 311ATTRIBUTE_GROUPS(pwm_chip);
 312
 313static struct class pwm_class = {
 314        .name = "pwm",
 315        .owner = THIS_MODULE,
 316        .dev_groups = pwm_chip_groups,
 317};
 318
 319static int pwmchip_sysfs_match(struct device *parent, const void *data)
 320{
 321        return dev_get_drvdata(parent) == data;
 322}
 323
 324void pwmchip_sysfs_export(struct pwm_chip *chip)
 325{
 326        struct device *parent;
 327
 328        /*
 329         * If device_create() fails the pwm_chip is still usable by
 330         * the kernel its just not exported.
 331         */
 332        parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
 333                               "pwmchip%d", chip->base);
 334        if (IS_ERR(parent)) {
 335                dev_warn(chip->dev,
 336                         "device_create failed for pwm_chip sysfs export\n");
 337        }
 338}
 339
 340void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 341{
 342        struct device *parent;
 343
 344        parent = class_find_device(&pwm_class, NULL, chip,
 345                                   pwmchip_sysfs_match);
 346        if (parent) {
 347                /* for class_find_device() */
 348                put_device(parent);
 349                device_unregister(parent);
 350        }
 351}
 352
 353static int __init pwm_sysfs_init(void)
 354{
 355        return class_register(&pwm_class);
 356}
 357subsys_initcall(pwm_sysfs_init);
 358