sysfs.c (11580B)
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 struct pwm_state suspend; 22}; 23 24static struct pwm_export *child_to_pwm_export(struct device *child) 25{ 26 return container_of(child, struct pwm_export, child); 27} 28 29static struct pwm_device *child_to_pwm_device(struct device *child) 30{ 31 struct pwm_export *export = child_to_pwm_export(child); 32 33 return export->pwm; 34} 35 36static ssize_t period_show(struct device *child, 37 struct device_attribute *attr, 38 char *buf) 39{ 40 const struct pwm_device *pwm = child_to_pwm_device(child); 41 struct pwm_state state; 42 43 pwm_get_state(pwm, &state); 44 45 return sprintf(buf, "%llu\n", state.period); 46} 47 48static ssize_t period_store(struct device *child, 49 struct device_attribute *attr, 50 const char *buf, size_t size) 51{ 52 struct pwm_export *export = child_to_pwm_export(child); 53 struct pwm_device *pwm = export->pwm; 54 struct pwm_state state; 55 u64 val; 56 int ret; 57 58 ret = kstrtou64(buf, 0, &val); 59 if (ret) 60 return ret; 61 62 mutex_lock(&export->lock); 63 pwm_get_state(pwm, &state); 64 state.period = val; 65 ret = pwm_apply_state(pwm, &state); 66 mutex_unlock(&export->lock); 67 68 return ret ? : size; 69} 70 71static ssize_t duty_cycle_show(struct device *child, 72 struct device_attribute *attr, 73 char *buf) 74{ 75 const struct pwm_device *pwm = child_to_pwm_device(child); 76 struct pwm_state state; 77 78 pwm_get_state(pwm, &state); 79 80 return sprintf(buf, "%llu\n", state.duty_cycle); 81} 82 83static ssize_t duty_cycle_store(struct device *child, 84 struct device_attribute *attr, 85 const char *buf, size_t size) 86{ 87 struct pwm_export *export = child_to_pwm_export(child); 88 struct pwm_device *pwm = export->pwm; 89 struct pwm_state state; 90 u64 val; 91 int ret; 92 93 ret = kstrtou64(buf, 0, &val); 94 if (ret) 95 return ret; 96 97 mutex_lock(&export->lock); 98 pwm_get_state(pwm, &state); 99 state.duty_cycle = val; 100 ret = pwm_apply_state(pwm, &state); 101 mutex_unlock(&export->lock); 102 103 return ret ? : size; 104} 105 106static ssize_t enable_show(struct device *child, 107 struct device_attribute *attr, 108 char *buf) 109{ 110 const struct pwm_device *pwm = child_to_pwm_device(child); 111 struct pwm_state state; 112 113 pwm_get_state(pwm, &state); 114 115 return sprintf(buf, "%d\n", state.enabled); 116} 117 118static ssize_t enable_store(struct device *child, 119 struct device_attribute *attr, 120 const char *buf, size_t size) 121{ 122 struct pwm_export *export = child_to_pwm_export(child); 123 struct pwm_device *pwm = export->pwm; 124 struct pwm_state state; 125 int val, ret; 126 127 ret = kstrtoint(buf, 0, &val); 128 if (ret) 129 return ret; 130 131 mutex_lock(&export->lock); 132 133 pwm_get_state(pwm, &state); 134 135 switch (val) { 136 case 0: 137 state.enabled = false; 138 break; 139 case 1: 140 state.enabled = true; 141 break; 142 default: 143 ret = -EINVAL; 144 goto unlock; 145 } 146 147 ret = pwm_apply_state(pwm, &state); 148 149unlock: 150 mutex_unlock(&export->lock); 151 return ret ? : size; 152} 153 154static ssize_t polarity_show(struct device *child, 155 struct device_attribute *attr, 156 char *buf) 157{ 158 const struct pwm_device *pwm = child_to_pwm_device(child); 159 const char *polarity = "unknown"; 160 struct pwm_state state; 161 162 pwm_get_state(pwm, &state); 163 164 switch (state.polarity) { 165 case PWM_POLARITY_NORMAL: 166 polarity = "normal"; 167 break; 168 169 case PWM_POLARITY_INVERSED: 170 polarity = "inversed"; 171 break; 172 } 173 174 return sprintf(buf, "%s\n", polarity); 175} 176 177static ssize_t polarity_store(struct device *child, 178 struct device_attribute *attr, 179 const char *buf, size_t size) 180{ 181 struct pwm_export *export = child_to_pwm_export(child); 182 struct pwm_device *pwm = export->pwm; 183 enum pwm_polarity polarity; 184 struct pwm_state state; 185 int ret; 186 187 if (sysfs_streq(buf, "normal")) 188 polarity = PWM_POLARITY_NORMAL; 189 else if (sysfs_streq(buf, "inversed")) 190 polarity = PWM_POLARITY_INVERSED; 191 else 192 return -EINVAL; 193 194 mutex_lock(&export->lock); 195 pwm_get_state(pwm, &state); 196 state.polarity = polarity; 197 ret = pwm_apply_state(pwm, &state); 198 mutex_unlock(&export->lock); 199 200 return ret ? : size; 201} 202 203static ssize_t capture_show(struct device *child, 204 struct device_attribute *attr, 205 char *buf) 206{ 207 struct pwm_device *pwm = child_to_pwm_device(child); 208 struct pwm_capture result; 209 int ret; 210 211 ret = pwm_capture(pwm, &result, jiffies_to_msecs(HZ)); 212 if (ret) 213 return ret; 214 215 return sprintf(buf, "%u %u\n", result.period, result.duty_cycle); 216} 217 218static DEVICE_ATTR_RW(period); 219static DEVICE_ATTR_RW(duty_cycle); 220static DEVICE_ATTR_RW(enable); 221static DEVICE_ATTR_RW(polarity); 222static DEVICE_ATTR_RO(capture); 223 224static struct attribute *pwm_attrs[] = { 225 &dev_attr_period.attr, 226 &dev_attr_duty_cycle.attr, 227 &dev_attr_enable.attr, 228 &dev_attr_polarity.attr, 229 &dev_attr_capture.attr, 230 NULL 231}; 232ATTRIBUTE_GROUPS(pwm); 233 234static void pwm_export_release(struct device *child) 235{ 236 struct pwm_export *export = child_to_pwm_export(child); 237 238 kfree(export); 239} 240 241static int pwm_export_child(struct device *parent, struct pwm_device *pwm) 242{ 243 struct pwm_export *export; 244 char *pwm_prop[2]; 245 int ret; 246 247 if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) 248 return -EBUSY; 249 250 export = kzalloc(sizeof(*export), GFP_KERNEL); 251 if (!export) { 252 clear_bit(PWMF_EXPORTED, &pwm->flags); 253 return -ENOMEM; 254 } 255 256 export->pwm = pwm; 257 mutex_init(&export->lock); 258 259 export->child.release = pwm_export_release; 260 export->child.parent = parent; 261 export->child.devt = MKDEV(0, 0); 262 export->child.groups = pwm_groups; 263 dev_set_name(&export->child, "pwm%u", pwm->hwpwm); 264 265 ret = device_register(&export->child); 266 if (ret) { 267 clear_bit(PWMF_EXPORTED, &pwm->flags); 268 put_device(&export->child); 269 export = NULL; 270 return ret; 271 } 272 pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm); 273 pwm_prop[1] = NULL; 274 kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); 275 kfree(pwm_prop[0]); 276 277 return 0; 278} 279 280static int pwm_unexport_match(struct device *child, void *data) 281{ 282 return child_to_pwm_device(child) == data; 283} 284 285static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) 286{ 287 struct device *child; 288 char *pwm_prop[2]; 289 290 if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) 291 return -ENODEV; 292 293 child = device_find_child(parent, pwm, pwm_unexport_match); 294 if (!child) 295 return -ENODEV; 296 297 pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm); 298 pwm_prop[1] = NULL; 299 kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); 300 kfree(pwm_prop[0]); 301 302 /* for device_find_child() */ 303 put_device(child); 304 device_unregister(child); 305 pwm_put(pwm); 306 307 return 0; 308} 309 310static ssize_t export_store(struct device *parent, 311 struct device_attribute *attr, 312 const char *buf, size_t len) 313{ 314 struct pwm_chip *chip = dev_get_drvdata(parent); 315 struct pwm_device *pwm; 316 unsigned int hwpwm; 317 int ret; 318 319 ret = kstrtouint(buf, 0, &hwpwm); 320 if (ret < 0) 321 return ret; 322 323 if (hwpwm >= chip->npwm) 324 return -ENODEV; 325 326 pwm = pwm_request_from_chip(chip, hwpwm, "sysfs"); 327 if (IS_ERR(pwm)) 328 return PTR_ERR(pwm); 329 330 ret = pwm_export_child(parent, pwm); 331 if (ret < 0) 332 pwm_put(pwm); 333 334 return ret ? : len; 335} 336static DEVICE_ATTR_WO(export); 337 338static ssize_t unexport_store(struct device *parent, 339 struct device_attribute *attr, 340 const char *buf, size_t len) 341{ 342 struct pwm_chip *chip = dev_get_drvdata(parent); 343 unsigned int hwpwm; 344 int ret; 345 346 ret = kstrtouint(buf, 0, &hwpwm); 347 if (ret < 0) 348 return ret; 349 350 if (hwpwm >= chip->npwm) 351 return -ENODEV; 352 353 ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]); 354 355 return ret ? : len; 356} 357static DEVICE_ATTR_WO(unexport); 358 359static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 360 char *buf) 361{ 362 const struct pwm_chip *chip = dev_get_drvdata(parent); 363 364 return sprintf(buf, "%u\n", chip->npwm); 365} 366static DEVICE_ATTR_RO(npwm); 367 368static struct attribute *pwm_chip_attrs[] = { 369 &dev_attr_export.attr, 370 &dev_attr_unexport.attr, 371 &dev_attr_npwm.attr, 372 NULL, 373}; 374ATTRIBUTE_GROUPS(pwm_chip); 375 376/* takes export->lock on success */ 377static struct pwm_export *pwm_class_get_state(struct device *parent, 378 struct pwm_device *pwm, 379 struct pwm_state *state) 380{ 381 struct device *child; 382 struct pwm_export *export; 383 384 if (!test_bit(PWMF_EXPORTED, &pwm->flags)) 385 return NULL; 386 387 child = device_find_child(parent, pwm, pwm_unexport_match); 388 if (!child) 389 return NULL; 390 391 export = child_to_pwm_export(child); 392 put_device(child); /* for device_find_child() */ 393 394 mutex_lock(&export->lock); 395 pwm_get_state(pwm, state); 396 397 return export; 398} 399 400static int pwm_class_apply_state(struct pwm_export *export, 401 struct pwm_device *pwm, 402 struct pwm_state *state) 403{ 404 int ret = pwm_apply_state(pwm, state); 405 406 /* release lock taken in pwm_class_get_state */ 407 mutex_unlock(&export->lock); 408 409 return ret; 410} 411 412static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm) 413{ 414 struct pwm_chip *chip = dev_get_drvdata(parent); 415 unsigned int i; 416 int ret = 0; 417 418 for (i = 0; i < npwm; i++) { 419 struct pwm_device *pwm = &chip->pwms[i]; 420 struct pwm_state state; 421 struct pwm_export *export; 422 423 export = pwm_class_get_state(parent, pwm, &state); 424 if (!export) 425 continue; 426 427 state.enabled = export->suspend.enabled; 428 ret = pwm_class_apply_state(export, pwm, &state); 429 if (ret < 0) 430 break; 431 } 432 433 return ret; 434} 435 436static int __maybe_unused pwm_class_suspend(struct device *parent) 437{ 438 struct pwm_chip *chip = dev_get_drvdata(parent); 439 unsigned int i; 440 int ret = 0; 441 442 for (i = 0; i < chip->npwm; i++) { 443 struct pwm_device *pwm = &chip->pwms[i]; 444 struct pwm_state state; 445 struct pwm_export *export; 446 447 export = pwm_class_get_state(parent, pwm, &state); 448 if (!export) 449 continue; 450 451 export->suspend = state; 452 state.enabled = false; 453 ret = pwm_class_apply_state(export, pwm, &state); 454 if (ret < 0) { 455 /* 456 * roll back the PWM devices that were disabled by 457 * this suspend function. 458 */ 459 pwm_class_resume_npwm(parent, i); 460 break; 461 } 462 } 463 464 return ret; 465} 466 467static int __maybe_unused pwm_class_resume(struct device *parent) 468{ 469 struct pwm_chip *chip = dev_get_drvdata(parent); 470 471 return pwm_class_resume_npwm(parent, chip->npwm); 472} 473 474static SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_resume); 475 476static struct class pwm_class = { 477 .name = "pwm", 478 .owner = THIS_MODULE, 479 .dev_groups = pwm_chip_groups, 480 .pm = &pwm_class_pm_ops, 481}; 482 483static int pwmchip_sysfs_match(struct device *parent, const void *data) 484{ 485 return dev_get_drvdata(parent) == data; 486} 487 488void pwmchip_sysfs_export(struct pwm_chip *chip) 489{ 490 struct device *parent; 491 492 /* 493 * If device_create() fails the pwm_chip is still usable by 494 * the kernel it's just not exported. 495 */ 496 parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip, 497 "pwmchip%d", chip->base); 498 if (IS_ERR(parent)) { 499 dev_warn(chip->dev, 500 "device_create failed for pwm_chip sysfs export\n"); 501 } 502} 503 504void pwmchip_sysfs_unexport(struct pwm_chip *chip) 505{ 506 struct device *parent; 507 unsigned int i; 508 509 parent = class_find_device(&pwm_class, NULL, chip, 510 pwmchip_sysfs_match); 511 if (!parent) 512 return; 513 514 for (i = 0; i < chip->npwm; i++) { 515 struct pwm_device *pwm = &chip->pwms[i]; 516 517 if (test_bit(PWMF_EXPORTED, &pwm->flags)) 518 pwm_unexport_child(parent, pwm); 519 } 520 521 put_device(parent); 522 device_unregister(parent); 523} 524 525static int __init pwm_sysfs_init(void) 526{ 527 return class_register(&pwm_class); 528} 529subsys_initcall(pwm_sysfs_init);