Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.17-rc4 347 lines 7.9 kB view raw
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 pwm_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->period); 50} 51 52static ssize_t pwm_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->duty_cycle, val); 65 66 return ret ? : size; 67} 68 69static ssize_t pwm_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->duty_cycle); 76} 77 78static ssize_t pwm_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->period); 91 92 return ret ? : size; 93} 94 95static ssize_t pwm_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 int enabled = test_bit(PWMF_ENABLED, &pwm->flags); 101 102 return sprintf(buf, "%d\n", enabled); 103} 104 105static ssize_t pwm_enable_store(struct device *child, 106 struct device_attribute *attr, 107 const char *buf, size_t size) 108{ 109 struct pwm_device *pwm = child_to_pwm_device(child); 110 int val, ret; 111 112 ret = kstrtoint(buf, 0, &val); 113 if (ret) 114 return ret; 115 116 switch (val) { 117 case 0: 118 pwm_disable(pwm); 119 break; 120 case 1: 121 ret = pwm_enable(pwm); 122 break; 123 default: 124 ret = -EINVAL; 125 break; 126 } 127 128 return ret ? : size; 129} 130 131static ssize_t pwm_polarity_show(struct device *child, 132 struct device_attribute *attr, 133 char *buf) 134{ 135 const struct pwm_device *pwm = child_to_pwm_device(child); 136 137 return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal"); 138} 139 140static ssize_t pwm_polarity_store(struct device *child, 141 struct device_attribute *attr, 142 const char *buf, size_t size) 143{ 144 struct pwm_device *pwm = child_to_pwm_device(child); 145 enum pwm_polarity polarity; 146 int ret; 147 148 if (sysfs_streq(buf, "normal")) 149 polarity = PWM_POLARITY_NORMAL; 150 else if (sysfs_streq(buf, "inversed")) 151 polarity = PWM_POLARITY_INVERSED; 152 else 153 return -EINVAL; 154 155 ret = pwm_set_polarity(pwm, polarity); 156 157 return ret ? : size; 158} 159 160static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); 161static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store); 162static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store); 163static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store); 164 165static struct attribute *pwm_attrs[] = { 166 &dev_attr_period.attr, 167 &dev_attr_duty_cycle.attr, 168 &dev_attr_enable.attr, 169 &dev_attr_polarity.attr, 170 NULL 171}; 172ATTRIBUTE_GROUPS(pwm); 173 174static void pwm_export_release(struct device *child) 175{ 176 struct pwm_export *export = child_to_pwm_export(child); 177 178 kfree(export); 179} 180 181static int pwm_export_child(struct device *parent, struct pwm_device *pwm) 182{ 183 struct pwm_export *export; 184 int ret; 185 186 if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) 187 return -EBUSY; 188 189 export = kzalloc(sizeof(*export), GFP_KERNEL); 190 if (!export) { 191 clear_bit(PWMF_EXPORTED, &pwm->flags); 192 return -ENOMEM; 193 } 194 195 export->pwm = pwm; 196 197 export->child.release = pwm_export_release; 198 export->child.parent = parent; 199 export->child.devt = MKDEV(0, 0); 200 export->child.groups = pwm_groups; 201 dev_set_name(&export->child, "pwm%u", pwm->hwpwm); 202 203 ret = device_register(&export->child); 204 if (ret) { 205 clear_bit(PWMF_EXPORTED, &pwm->flags); 206 kfree(export); 207 return ret; 208 } 209 210 return 0; 211} 212 213static int pwm_unexport_match(struct device *child, void *data) 214{ 215 return child_to_pwm_device(child) == data; 216} 217 218static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) 219{ 220 struct device *child; 221 222 if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) 223 return -ENODEV; 224 225 child = device_find_child(parent, pwm, pwm_unexport_match); 226 if (!child) 227 return -ENODEV; 228 229 /* for device_find_child() */ 230 put_device(child); 231 device_unregister(child); 232 pwm_put(pwm); 233 234 return 0; 235} 236 237static ssize_t pwm_export_store(struct device *parent, 238 struct device_attribute *attr, 239 const char *buf, size_t len) 240{ 241 struct pwm_chip *chip = dev_get_drvdata(parent); 242 struct pwm_device *pwm; 243 unsigned int hwpwm; 244 int ret; 245 246 ret = kstrtouint(buf, 0, &hwpwm); 247 if (ret < 0) 248 return ret; 249 250 if (hwpwm >= chip->npwm) 251 return -ENODEV; 252 253 pwm = pwm_request_from_chip(chip, hwpwm, "sysfs"); 254 if (IS_ERR(pwm)) 255 return PTR_ERR(pwm); 256 257 ret = pwm_export_child(parent, pwm); 258 if (ret < 0) 259 pwm_put(pwm); 260 261 return ret ? : len; 262} 263static DEVICE_ATTR(export, 0200, NULL, pwm_export_store); 264 265static ssize_t pwm_unexport_store(struct device *parent, 266 struct device_attribute *attr, 267 const char *buf, size_t len) 268{ 269 struct pwm_chip *chip = dev_get_drvdata(parent); 270 unsigned int hwpwm; 271 int ret; 272 273 ret = kstrtouint(buf, 0, &hwpwm); 274 if (ret < 0) 275 return ret; 276 277 if (hwpwm >= chip->npwm) 278 return -ENODEV; 279 280 ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]); 281 282 return ret ? : len; 283} 284static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store); 285 286static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 287 char *buf) 288{ 289 const struct pwm_chip *chip = dev_get_drvdata(parent); 290 291 return sprintf(buf, "%u\n", chip->npwm); 292} 293static DEVICE_ATTR_RO(npwm); 294 295static struct attribute *pwm_chip_attrs[] = { 296 &dev_attr_export.attr, 297 &dev_attr_unexport.attr, 298 &dev_attr_npwm.attr, 299 NULL, 300}; 301ATTRIBUTE_GROUPS(pwm_chip); 302 303static struct class pwm_class = { 304 .name = "pwm", 305 .owner = THIS_MODULE, 306 .dev_groups = pwm_chip_groups, 307}; 308 309static int pwmchip_sysfs_match(struct device *parent, const void *data) 310{ 311 return dev_get_drvdata(parent) == data; 312} 313 314void pwmchip_sysfs_export(struct pwm_chip *chip) 315{ 316 struct device *parent; 317 318 /* 319 * If device_create() fails the pwm_chip is still usable by 320 * the kernel its just not exported. 321 */ 322 parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip, 323 "pwmchip%d", chip->base); 324 if (IS_ERR(parent)) { 325 dev_warn(chip->dev, 326 "device_create failed for pwm_chip sysfs export\n"); 327 } 328} 329 330void pwmchip_sysfs_unexport(struct pwm_chip *chip) 331{ 332 struct device *parent; 333 334 parent = class_find_device(&pwm_class, NULL, chip, 335 pwmchip_sysfs_match); 336 if (parent) { 337 /* for class_find_device() */ 338 put_device(parent); 339 device_unregister(parent); 340 } 341} 342 343static int __init pwm_sysfs_init(void) 344{ 345 return class_register(&pwm_class); 346} 347subsys_initcall(pwm_sysfs_init);