13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 276abbddeSH Hartley Sweeten /* 376abbddeSH Hartley Sweeten * A simple sysfs interface for the generic PWM framework 476abbddeSH Hartley Sweeten * 576abbddeSH Hartley Sweeten * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com> 676abbddeSH Hartley Sweeten * 776abbddeSH Hartley Sweeten * Based on previous work by Lars Poeschel <poeschel@lemonage.de> 876abbddeSH Hartley Sweeten */ 976abbddeSH Hartley Sweeten 1076abbddeSH Hartley Sweeten #include <linux/device.h> 1176abbddeSH Hartley Sweeten #include <linux/mutex.h> 1276abbddeSH Hartley Sweeten #include <linux/err.h> 1376abbddeSH Hartley Sweeten #include <linux/slab.h> 1476abbddeSH Hartley Sweeten #include <linux/kdev_t.h> 1576abbddeSH Hartley Sweeten #include <linux/pwm.h> 1676abbddeSH Hartley Sweeten 1776abbddeSH Hartley Sweeten struct pwm_export { 1876abbddeSH Hartley Sweeten struct device child; 1976abbddeSH Hartley Sweeten struct pwm_device *pwm; 20459a25afSBoris BREZILLON struct mutex lock; 2176abbddeSH Hartley Sweeten }; 2276abbddeSH Hartley Sweeten 2376abbddeSH Hartley Sweeten static struct pwm_export *child_to_pwm_export(struct device *child) 2476abbddeSH Hartley Sweeten { 2576abbddeSH Hartley Sweeten return container_of(child, struct pwm_export, child); 2676abbddeSH Hartley Sweeten } 2776abbddeSH Hartley Sweeten 2876abbddeSH Hartley Sweeten static struct pwm_device *child_to_pwm_device(struct device *child) 2976abbddeSH Hartley Sweeten { 3076abbddeSH Hartley Sweeten struct pwm_export *export = child_to_pwm_export(child); 3176abbddeSH Hartley Sweeten 3276abbddeSH Hartley Sweeten return export->pwm; 3376abbddeSH Hartley Sweeten } 3476abbddeSH Hartley Sweeten 3565cdc691SOlliver Schinagl static ssize_t period_show(struct device *child, 3676abbddeSH Hartley Sweeten struct device_attribute *attr, 3776abbddeSH Hartley Sweeten char *buf) 3876abbddeSH Hartley Sweeten { 3976abbddeSH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 4039100ceeSBoris Brezillon struct pwm_state state; 4176abbddeSH Hartley Sweeten 4239100ceeSBoris Brezillon pwm_get_state(pwm, &state); 4339100ceeSBoris Brezillon 4439100ceeSBoris Brezillon return sprintf(buf, "%u\n", state.period); 4576abbddeSH Hartley Sweeten } 4676abbddeSH Hartley Sweeten 4765cdc691SOlliver Schinagl static ssize_t period_store(struct device *child, 4876abbddeSH Hartley Sweeten struct device_attribute *attr, 4976abbddeSH Hartley Sweeten const char *buf, size_t size) 5076abbddeSH Hartley Sweeten { 51459a25afSBoris BREZILLON struct pwm_export *export = child_to_pwm_export(child); 52459a25afSBoris BREZILLON struct pwm_device *pwm = export->pwm; 5339100ceeSBoris Brezillon struct pwm_state state; 5476abbddeSH Hartley Sweeten unsigned int val; 5576abbddeSH Hartley Sweeten int ret; 5676abbddeSH Hartley Sweeten 5776abbddeSH Hartley Sweeten ret = kstrtouint(buf, 0, &val); 5876abbddeSH Hartley Sweeten if (ret) 5976abbddeSH Hartley Sweeten return ret; 6076abbddeSH Hartley Sweeten 61459a25afSBoris BREZILLON mutex_lock(&export->lock); 6239100ceeSBoris Brezillon pwm_get_state(pwm, &state); 6339100ceeSBoris Brezillon state.period = val; 6439100ceeSBoris Brezillon ret = pwm_apply_state(pwm, &state); 65459a25afSBoris BREZILLON mutex_unlock(&export->lock); 6676abbddeSH Hartley Sweeten 6776abbddeSH Hartley Sweeten return ret ? : size; 6876abbddeSH Hartley Sweeten } 6976abbddeSH Hartley Sweeten 7065cdc691SOlliver Schinagl static ssize_t duty_cycle_show(struct device *child, 7176abbddeSH Hartley Sweeten struct device_attribute *attr, 7276abbddeSH Hartley Sweeten char *buf) 7376abbddeSH Hartley Sweeten { 7476abbddeSH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 7539100ceeSBoris Brezillon struct pwm_state state; 7676abbddeSH Hartley Sweeten 7739100ceeSBoris Brezillon pwm_get_state(pwm, &state); 7839100ceeSBoris Brezillon 7939100ceeSBoris Brezillon return sprintf(buf, "%u\n", state.duty_cycle); 8076abbddeSH Hartley Sweeten } 8176abbddeSH Hartley Sweeten 8265cdc691SOlliver Schinagl static ssize_t duty_cycle_store(struct device *child, 8376abbddeSH Hartley Sweeten struct device_attribute *attr, 8476abbddeSH Hartley Sweeten const char *buf, size_t size) 8576abbddeSH Hartley Sweeten { 86459a25afSBoris BREZILLON struct pwm_export *export = child_to_pwm_export(child); 87459a25afSBoris BREZILLON struct pwm_device *pwm = export->pwm; 8839100ceeSBoris Brezillon struct pwm_state state; 8976abbddeSH Hartley Sweeten unsigned int val; 9076abbddeSH Hartley Sweeten int ret; 9176abbddeSH Hartley Sweeten 9276abbddeSH Hartley Sweeten ret = kstrtouint(buf, 0, &val); 9376abbddeSH Hartley Sweeten if (ret) 9476abbddeSH Hartley Sweeten return ret; 9576abbddeSH Hartley Sweeten 96459a25afSBoris BREZILLON mutex_lock(&export->lock); 9739100ceeSBoris Brezillon pwm_get_state(pwm, &state); 9839100ceeSBoris Brezillon state.duty_cycle = val; 9939100ceeSBoris Brezillon ret = pwm_apply_state(pwm, &state); 100459a25afSBoris BREZILLON mutex_unlock(&export->lock); 10176abbddeSH Hartley Sweeten 10276abbddeSH Hartley Sweeten return ret ? : size; 10376abbddeSH Hartley Sweeten } 10476abbddeSH Hartley Sweeten 10565cdc691SOlliver Schinagl static ssize_t enable_show(struct device *child, 10676abbddeSH Hartley Sweeten struct device_attribute *attr, 10776abbddeSH Hartley Sweeten char *buf) 10876abbddeSH Hartley Sweeten { 10976abbddeSH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 11039100ceeSBoris Brezillon struct pwm_state state; 11176abbddeSH Hartley Sweeten 11239100ceeSBoris Brezillon pwm_get_state(pwm, &state); 11339100ceeSBoris Brezillon 11439100ceeSBoris Brezillon return sprintf(buf, "%d\n", state.enabled); 11576abbddeSH Hartley Sweeten } 11676abbddeSH Hartley Sweeten 11765cdc691SOlliver Schinagl static ssize_t enable_store(struct device *child, 11876abbddeSH Hartley Sweeten struct device_attribute *attr, 11976abbddeSH Hartley Sweeten const char *buf, size_t size) 12076abbddeSH Hartley Sweeten { 121459a25afSBoris BREZILLON struct pwm_export *export = child_to_pwm_export(child); 122459a25afSBoris BREZILLON struct pwm_device *pwm = export->pwm; 12339100ceeSBoris Brezillon struct pwm_state state; 12476abbddeSH Hartley Sweeten int val, ret; 12576abbddeSH Hartley Sweeten 12676abbddeSH Hartley Sweeten ret = kstrtoint(buf, 0, &val); 12776abbddeSH Hartley Sweeten if (ret) 12876abbddeSH Hartley Sweeten return ret; 12976abbddeSH Hartley Sweeten 130459a25afSBoris BREZILLON mutex_lock(&export->lock); 131459a25afSBoris BREZILLON 13239100ceeSBoris Brezillon pwm_get_state(pwm, &state); 13339100ceeSBoris Brezillon 13476abbddeSH Hartley Sweeten switch (val) { 13576abbddeSH Hartley Sweeten case 0: 13639100ceeSBoris Brezillon state.enabled = false; 13776abbddeSH Hartley Sweeten break; 13876abbddeSH Hartley Sweeten case 1: 13939100ceeSBoris Brezillon state.enabled = true; 14076abbddeSH Hartley Sweeten break; 14176abbddeSH Hartley Sweeten default: 14276abbddeSH Hartley Sweeten ret = -EINVAL; 14339100ceeSBoris Brezillon goto unlock; 14476abbddeSH Hartley Sweeten } 14576abbddeSH Hartley Sweeten 146fe5aa34dSRyo Kodama ret = pwm_apply_state(pwm, &state); 147459a25afSBoris BREZILLON 14839100ceeSBoris Brezillon unlock: 14939100ceeSBoris Brezillon mutex_unlock(&export->lock); 15076abbddeSH Hartley Sweeten return ret ? : size; 15176abbddeSH Hartley Sweeten } 15276abbddeSH Hartley Sweeten 15365cdc691SOlliver Schinagl static ssize_t polarity_show(struct device *child, 15476abbddeSH Hartley Sweeten struct device_attribute *attr, 15576abbddeSH Hartley Sweeten char *buf) 15676abbddeSH Hartley Sweeten { 15776abbddeSH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 1585a063d87SThierry Reding const char *polarity = "unknown"; 15939100ceeSBoris Brezillon struct pwm_state state; 16076abbddeSH Hartley Sweeten 16139100ceeSBoris Brezillon pwm_get_state(pwm, &state); 16239100ceeSBoris Brezillon 16339100ceeSBoris Brezillon switch (state.polarity) { 1645a063d87SThierry Reding case PWM_POLARITY_NORMAL: 1655a063d87SThierry Reding polarity = "normal"; 1665a063d87SThierry Reding break; 1675a063d87SThierry Reding 1685a063d87SThierry Reding case PWM_POLARITY_INVERSED: 1695a063d87SThierry Reding polarity = "inversed"; 1705a063d87SThierry Reding break; 1715a063d87SThierry Reding } 1725a063d87SThierry Reding 1735a063d87SThierry Reding return sprintf(buf, "%s\n", polarity); 17476abbddeSH Hartley Sweeten } 17576abbddeSH Hartley Sweeten 17665cdc691SOlliver Schinagl static ssize_t polarity_store(struct device *child, 17776abbddeSH Hartley Sweeten struct device_attribute *attr, 17876abbddeSH Hartley Sweeten const char *buf, size_t size) 17976abbddeSH Hartley Sweeten { 180459a25afSBoris BREZILLON struct pwm_export *export = child_to_pwm_export(child); 181459a25afSBoris BREZILLON struct pwm_device *pwm = export->pwm; 18276abbddeSH Hartley Sweeten enum pwm_polarity polarity; 18339100ceeSBoris Brezillon struct pwm_state state; 18476abbddeSH Hartley Sweeten int ret; 18576abbddeSH Hartley Sweeten 18676abbddeSH Hartley Sweeten if (sysfs_streq(buf, "normal")) 18776abbddeSH Hartley Sweeten polarity = PWM_POLARITY_NORMAL; 18876abbddeSH Hartley Sweeten else if (sysfs_streq(buf, "inversed")) 18976abbddeSH Hartley Sweeten polarity = PWM_POLARITY_INVERSED; 19076abbddeSH Hartley Sweeten else 19176abbddeSH Hartley Sweeten return -EINVAL; 19276abbddeSH Hartley Sweeten 193459a25afSBoris BREZILLON mutex_lock(&export->lock); 19439100ceeSBoris Brezillon pwm_get_state(pwm, &state); 19539100ceeSBoris Brezillon state.polarity = polarity; 19639100ceeSBoris Brezillon ret = pwm_apply_state(pwm, &state); 197459a25afSBoris BREZILLON mutex_unlock(&export->lock); 19876abbddeSH Hartley Sweeten 19976abbddeSH Hartley Sweeten return ret ? : size; 20076abbddeSH Hartley Sweeten } 20176abbddeSH Hartley Sweeten 2021a366fe9SLee Jones static ssize_t capture_show(struct device *child, 2031a366fe9SLee Jones struct device_attribute *attr, 2041a366fe9SLee Jones char *buf) 2051a366fe9SLee Jones { 2061a366fe9SLee Jones struct pwm_device *pwm = child_to_pwm_device(child); 2071a366fe9SLee Jones struct pwm_capture result; 2081a366fe9SLee Jones int ret; 2091a366fe9SLee Jones 2101a366fe9SLee Jones ret = pwm_capture(pwm, &result, jiffies_to_msecs(HZ)); 2111a366fe9SLee Jones if (ret) 2121a366fe9SLee Jones return ret; 2131a366fe9SLee Jones 2141a366fe9SLee Jones return sprintf(buf, "%u %u\n", result.period, result.duty_cycle); 2151a366fe9SLee Jones } 2161a366fe9SLee Jones 21765cdc691SOlliver Schinagl static DEVICE_ATTR_RW(period); 21865cdc691SOlliver Schinagl static DEVICE_ATTR_RW(duty_cycle); 21965cdc691SOlliver Schinagl static DEVICE_ATTR_RW(enable); 22065cdc691SOlliver Schinagl static DEVICE_ATTR_RW(polarity); 2211a366fe9SLee Jones static DEVICE_ATTR_RO(capture); 22276abbddeSH Hartley Sweeten 22376abbddeSH Hartley Sweeten static struct attribute *pwm_attrs[] = { 22476abbddeSH Hartley Sweeten &dev_attr_period.attr, 22576abbddeSH Hartley Sweeten &dev_attr_duty_cycle.attr, 22676abbddeSH Hartley Sweeten &dev_attr_enable.attr, 22776abbddeSH Hartley Sweeten &dev_attr_polarity.attr, 2281a366fe9SLee Jones &dev_attr_capture.attr, 22976abbddeSH Hartley Sweeten NULL 23076abbddeSH Hartley Sweeten }; 2316ca142adSAxel Lin ATTRIBUTE_GROUPS(pwm); 23276abbddeSH Hartley Sweeten 23376abbddeSH Hartley Sweeten static void pwm_export_release(struct device *child) 23476abbddeSH Hartley Sweeten { 23576abbddeSH Hartley Sweeten struct pwm_export *export = child_to_pwm_export(child); 23676abbddeSH Hartley Sweeten 23776abbddeSH Hartley Sweeten kfree(export); 23876abbddeSH Hartley Sweeten } 23976abbddeSH Hartley Sweeten 24076abbddeSH Hartley Sweeten static int pwm_export_child(struct device *parent, struct pwm_device *pwm) 24176abbddeSH Hartley Sweeten { 24276abbddeSH Hartley Sweeten struct pwm_export *export; 243552c02e3SFabrice Gasnier char *pwm_prop[2]; 24476abbddeSH Hartley Sweeten int ret; 24576abbddeSH Hartley Sweeten 24676abbddeSH Hartley Sweeten if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) 24776abbddeSH Hartley Sweeten return -EBUSY; 24876abbddeSH Hartley Sweeten 24976abbddeSH Hartley Sweeten export = kzalloc(sizeof(*export), GFP_KERNEL); 25076abbddeSH Hartley Sweeten if (!export) { 25176abbddeSH Hartley Sweeten clear_bit(PWMF_EXPORTED, &pwm->flags); 25276abbddeSH Hartley Sweeten return -ENOMEM; 25376abbddeSH Hartley Sweeten } 25476abbddeSH Hartley Sweeten 25576abbddeSH Hartley Sweeten export->pwm = pwm; 256459a25afSBoris BREZILLON mutex_init(&export->lock); 25776abbddeSH Hartley Sweeten 25876abbddeSH Hartley Sweeten export->child.release = pwm_export_release; 25976abbddeSH Hartley Sweeten export->child.parent = parent; 26076abbddeSH Hartley Sweeten export->child.devt = MKDEV(0, 0); 2616ca142adSAxel Lin export->child.groups = pwm_groups; 26276abbddeSH Hartley Sweeten dev_set_name(&export->child, "pwm%u", pwm->hwpwm); 26376abbddeSH Hartley Sweeten 26476abbddeSH Hartley Sweeten ret = device_register(&export->child); 26576abbddeSH Hartley Sweeten if (ret) { 26676abbddeSH Hartley Sweeten clear_bit(PWMF_EXPORTED, &pwm->flags); 2678bbf5b42SArvind Yadav put_device(&export->child); 2688bbf5b42SArvind Yadav export = NULL; 26976abbddeSH Hartley Sweeten return ret; 27076abbddeSH Hartley Sweeten } 271552c02e3SFabrice Gasnier pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm); 272552c02e3SFabrice Gasnier pwm_prop[1] = NULL; 273552c02e3SFabrice Gasnier kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); 274552c02e3SFabrice Gasnier kfree(pwm_prop[0]); 27576abbddeSH Hartley Sweeten 27676abbddeSH Hartley Sweeten return 0; 27776abbddeSH Hartley Sweeten } 27876abbddeSH Hartley Sweeten 27976abbddeSH Hartley Sweeten static int pwm_unexport_match(struct device *child, void *data) 28076abbddeSH Hartley Sweeten { 28176abbddeSH Hartley Sweeten return child_to_pwm_device(child) == data; 28276abbddeSH Hartley Sweeten } 28376abbddeSH Hartley Sweeten 28476abbddeSH Hartley Sweeten static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) 28576abbddeSH Hartley Sweeten { 28676abbddeSH Hartley Sweeten struct device *child; 287552c02e3SFabrice Gasnier char *pwm_prop[2]; 28876abbddeSH Hartley Sweeten 28976abbddeSH Hartley Sweeten if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) 29076abbddeSH Hartley Sweeten return -ENODEV; 29176abbddeSH Hartley Sweeten 29276abbddeSH Hartley Sweeten child = device_find_child(parent, pwm, pwm_unexport_match); 29376abbddeSH Hartley Sweeten if (!child) 29476abbddeSH Hartley Sweeten return -ENODEV; 29576abbddeSH Hartley Sweeten 296552c02e3SFabrice Gasnier pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm); 297552c02e3SFabrice Gasnier pwm_prop[1] = NULL; 298552c02e3SFabrice Gasnier kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop); 299552c02e3SFabrice Gasnier kfree(pwm_prop[0]); 300552c02e3SFabrice Gasnier 30176abbddeSH Hartley Sweeten /* for device_find_child() */ 30276abbddeSH Hartley Sweeten put_device(child); 30376abbddeSH Hartley Sweeten device_unregister(child); 30476abbddeSH Hartley Sweeten pwm_put(pwm); 30576abbddeSH Hartley Sweeten 30676abbddeSH Hartley Sweeten return 0; 30776abbddeSH Hartley Sweeten } 30876abbddeSH Hartley Sweeten 30965cdc691SOlliver Schinagl static ssize_t export_store(struct device *parent, 31076abbddeSH Hartley Sweeten struct device_attribute *attr, 31176abbddeSH Hartley Sweeten const char *buf, size_t len) 31276abbddeSH Hartley Sweeten { 31376abbddeSH Hartley Sweeten struct pwm_chip *chip = dev_get_drvdata(parent); 31476abbddeSH Hartley Sweeten struct pwm_device *pwm; 31576abbddeSH Hartley Sweeten unsigned int hwpwm; 31676abbddeSH Hartley Sweeten int ret; 31776abbddeSH Hartley Sweeten 31876abbddeSH Hartley Sweeten ret = kstrtouint(buf, 0, &hwpwm); 31976abbddeSH Hartley Sweeten if (ret < 0) 32076abbddeSH Hartley Sweeten return ret; 32176abbddeSH Hartley Sweeten 32276abbddeSH Hartley Sweeten if (hwpwm >= chip->npwm) 32376abbddeSH Hartley Sweeten return -ENODEV; 32476abbddeSH Hartley Sweeten 32576abbddeSH Hartley Sweeten pwm = pwm_request_from_chip(chip, hwpwm, "sysfs"); 32676abbddeSH Hartley Sweeten if (IS_ERR(pwm)) 32776abbddeSH Hartley Sweeten return PTR_ERR(pwm); 32876abbddeSH Hartley Sweeten 32976abbddeSH Hartley Sweeten ret = pwm_export_child(parent, pwm); 33076abbddeSH Hartley Sweeten if (ret < 0) 33176abbddeSH Hartley Sweeten pwm_put(pwm); 33276abbddeSH Hartley Sweeten 33376abbddeSH Hartley Sweeten return ret ? : len; 33476abbddeSH Hartley Sweeten } 33565cdc691SOlliver Schinagl static DEVICE_ATTR_WO(export); 33676abbddeSH Hartley Sweeten 33765cdc691SOlliver Schinagl static ssize_t unexport_store(struct device *parent, 33876abbddeSH Hartley Sweeten struct device_attribute *attr, 33976abbddeSH Hartley Sweeten const char *buf, size_t len) 34076abbddeSH Hartley Sweeten { 34176abbddeSH Hartley Sweeten struct pwm_chip *chip = dev_get_drvdata(parent); 34276abbddeSH Hartley Sweeten unsigned int hwpwm; 34376abbddeSH Hartley Sweeten int ret; 34476abbddeSH Hartley Sweeten 34576abbddeSH Hartley Sweeten ret = kstrtouint(buf, 0, &hwpwm); 34676abbddeSH Hartley Sweeten if (ret < 0) 34776abbddeSH Hartley Sweeten return ret; 34876abbddeSH Hartley Sweeten 34976abbddeSH Hartley Sweeten if (hwpwm >= chip->npwm) 35076abbddeSH Hartley Sweeten return -ENODEV; 35176abbddeSH Hartley Sweeten 35276abbddeSH Hartley Sweeten ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]); 35376abbddeSH Hartley Sweeten 35476abbddeSH Hartley Sweeten return ret ? : len; 35576abbddeSH Hartley Sweeten } 35665cdc691SOlliver Schinagl static DEVICE_ATTR_WO(unexport); 35776abbddeSH Hartley Sweeten 3589da01759SGreg Kroah-Hartman static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 35976abbddeSH Hartley Sweeten char *buf) 36076abbddeSH Hartley Sweeten { 36176abbddeSH Hartley Sweeten const struct pwm_chip *chip = dev_get_drvdata(parent); 36276abbddeSH Hartley Sweeten 36376abbddeSH Hartley Sweeten return sprintf(buf, "%u\n", chip->npwm); 36476abbddeSH Hartley Sweeten } 3659da01759SGreg Kroah-Hartman static DEVICE_ATTR_RO(npwm); 36676abbddeSH Hartley Sweeten 3679da01759SGreg Kroah-Hartman static struct attribute *pwm_chip_attrs[] = { 3689da01759SGreg Kroah-Hartman &dev_attr_export.attr, 3699da01759SGreg Kroah-Hartman &dev_attr_unexport.attr, 3709da01759SGreg Kroah-Hartman &dev_attr_npwm.attr, 3719da01759SGreg Kroah-Hartman NULL, 37276abbddeSH Hartley Sweeten }; 3739da01759SGreg Kroah-Hartman ATTRIBUTE_GROUPS(pwm_chip); 37476abbddeSH Hartley Sweeten 37576abbddeSH Hartley Sweeten static struct class pwm_class = { 37676abbddeSH Hartley Sweeten .name = "pwm", 37776abbddeSH Hartley Sweeten .owner = THIS_MODULE, 3789da01759SGreg Kroah-Hartman .dev_groups = pwm_chip_groups, 37976abbddeSH Hartley Sweeten }; 38076abbddeSH Hartley Sweeten 38176abbddeSH Hartley Sweeten static int pwmchip_sysfs_match(struct device *parent, const void *data) 38276abbddeSH Hartley Sweeten { 38376abbddeSH Hartley Sweeten return dev_get_drvdata(parent) == data; 38476abbddeSH Hartley Sweeten } 38576abbddeSH Hartley Sweeten 38676abbddeSH Hartley Sweeten void pwmchip_sysfs_export(struct pwm_chip *chip) 38776abbddeSH Hartley Sweeten { 38876abbddeSH Hartley Sweeten struct device *parent; 38976abbddeSH Hartley Sweeten 39076abbddeSH Hartley Sweeten /* 39176abbddeSH Hartley Sweeten * If device_create() fails the pwm_chip is still usable by 3929ff06679SUwe Kleine-König * the kernel it's just not exported. 39376abbddeSH Hartley Sweeten */ 39476abbddeSH Hartley Sweeten parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip, 39576abbddeSH Hartley Sweeten "pwmchip%d", chip->base); 39676abbddeSH Hartley Sweeten if (IS_ERR(parent)) { 39776abbddeSH Hartley Sweeten dev_warn(chip->dev, 39876abbddeSH Hartley Sweeten "device_create failed for pwm_chip sysfs export\n"); 39976abbddeSH Hartley Sweeten } 40076abbddeSH Hartley Sweeten } 40176abbddeSH Hartley Sweeten 40276abbddeSH Hartley Sweeten void pwmchip_sysfs_unexport(struct pwm_chip *chip) 40376abbddeSH Hartley Sweeten { 40476abbddeSH Hartley Sweeten struct device *parent; 4050733424cSDavid Hsu unsigned int i; 4060733424cSDavid Hsu 4070733424cSDavid Hsu parent = class_find_device(&pwm_class, NULL, chip, 4080733424cSDavid Hsu pwmchip_sysfs_match); 4090733424cSDavid Hsu if (!parent) 4100733424cSDavid Hsu return; 4110733424cSDavid Hsu 4120733424cSDavid Hsu for (i = 0; i < chip->npwm; i++) { 4130733424cSDavid Hsu struct pwm_device *pwm = &chip->pwms[i]; 4140733424cSDavid Hsu 4150733424cSDavid Hsu if (test_bit(PWMF_EXPORTED, &pwm->flags)) 4160733424cSDavid Hsu pwm_unexport_child(parent, pwm); 4170733424cSDavid Hsu } 4180e1614acSJohan Hovold 4190e1614acSJohan Hovold put_device(parent); 420347ab948SPhong Hoang device_unregister(parent); 4210733424cSDavid Hsu } 4220733424cSDavid Hsu 42376abbddeSH Hartley Sweeten static int __init pwm_sysfs_init(void) 42476abbddeSH Hartley Sweeten { 42576abbddeSH Hartley Sweeten return class_register(&pwm_class); 42676abbddeSH Hartley Sweeten } 42776abbddeSH Hartley Sweeten subsys_initcall(pwm_sysfs_init); 428