176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten/* 276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * A simple sysfs interface for the generic PWM framework 376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * 476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com> 576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * 676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * Based on previous work by Lars Poeschel <poeschel@lemonage.de> 776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * 876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * This program is free software; you can redistribute it and/or modify 976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * it under the terms of the GNU General Public License as published by 1076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * the Free Software Foundation; either version 2, or (at your option) 1176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * any later version. 1276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * 1376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * This program is distributed in the hope that it will be useful, 1476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * but WITHOUT ANY WARRANTY; without even the implied warranty of 1576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * GNU General Public License for more details. 1776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten */ 1876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 1976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/device.h> 2076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/mutex.h> 2176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/err.h> 2276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/slab.h> 2376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/kdev_t.h> 2476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten#include <linux/pwm.h> 2576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 2676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstruct pwm_export { 2776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device child; 2876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm; 2976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten}; 3076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 3176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic struct pwm_export *child_to_pwm_export(struct device *child) 3276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 3376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return container_of(child, struct pwm_export, child); 3476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 3576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 3676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic struct pwm_device *child_to_pwm_device(struct device *child) 3776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 3876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_export *export = child_to_pwm_export(child); 3976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 4076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return export->pwm; 4176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 4276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 4376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_period_show(struct device *child, 4476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 4576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten char *buf) 4676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 4776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 4876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 4976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return sprintf(buf, "%u\n", pwm->period); 5076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 5176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 5276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_period_store(struct device *child, 5376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 5476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t size) 5576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 5676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm = child_to_pwm_device(child); 5776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten unsigned int val; 5876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 5976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 6076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = kstrtouint(buf, 0, &val); 6176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret) 6276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 6376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 6476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_config(pwm, pwm->duty_cycle, val); 6576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 6676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : size; 6776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 6876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 6976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_duty_cycle_show(struct device *child, 7076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 7176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten char *buf) 7276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 7376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 7476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 7576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return sprintf(buf, "%u\n", pwm->duty_cycle); 7676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 7776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 7876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_duty_cycle_store(struct device *child, 7976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 8076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t size) 8176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 8276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm = child_to_pwm_device(child); 8376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten unsigned int val; 8476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 8576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 8676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = kstrtouint(buf, 0, &val); 8776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret) 8876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 8976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 9076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_config(pwm, val, pwm->period); 9176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 9276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : size; 9376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 9476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 9576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_enable_show(struct device *child, 9676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 9776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten char *buf) 9876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 9976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 10076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int enabled = test_bit(PWMF_ENABLED, &pwm->flags); 10176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 10276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return sprintf(buf, "%d\n", enabled); 10376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 10476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 10576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_enable_store(struct device *child, 10676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 10776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t size) 10876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 10976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm = child_to_pwm_device(child); 11076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int val, ret; 11176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 11276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = kstrtoint(buf, 0, &val); 11376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret) 11476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 11576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 11676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten switch (val) { 11776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten case 0: 11876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten pwm_disable(pwm); 11976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten break; 12076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten case 1: 12176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_enable(pwm); 12276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten break; 12376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten default: 12476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = -EINVAL; 12576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten break; 12676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten } 12776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 12876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : size; 12976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 13076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 13176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_polarity_show(struct device *child, 13276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 13376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten char *buf) 13476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 13576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const struct pwm_device *pwm = child_to_pwm_device(child); 13676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 13776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal"); 13876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 13976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 14076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_polarity_store(struct device *child, 14176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 14276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t size) 14376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 14476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm = child_to_pwm_device(child); 14576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten enum pwm_polarity polarity; 14676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 14776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 14876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (sysfs_streq(buf, "normal")) 14976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten polarity = PWM_POLARITY_NORMAL; 15076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten else if (sysfs_streq(buf, "inversed")) 15176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten polarity = PWM_POLARITY_INVERSED; 15276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten else 15376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -EINVAL; 15476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 15576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_set_polarity(pwm, polarity); 15676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 15776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : size; 15876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 15976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 16076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); 16176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store); 16276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store); 16376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store); 16476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 16576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic struct attribute *pwm_attrs[] = { 16676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten &dev_attr_period.attr, 16776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten &dev_attr_duty_cycle.attr, 16876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten &dev_attr_enable.attr, 16976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten &dev_attr_polarity.attr, 17076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten NULL 17176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten}; 1726ca142ad0d1bdf8dd116351b7b9a2bc5670d5271Axel LinATTRIBUTE_GROUPS(pwm); 17376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 17476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic void pwm_export_release(struct device *child) 17576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 17676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_export *export = child_to_pwm_export(child); 17776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 17876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten kfree(export); 17976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 18076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 18176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic int pwm_export_child(struct device *parent, struct pwm_device *pwm) 18276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 18376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_export *export; 18476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 18576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 18676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) 18776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -EBUSY; 18876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 18976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten export = kzalloc(sizeof(*export), GFP_KERNEL); 19076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (!export) { 19176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten clear_bit(PWMF_EXPORTED, &pwm->flags); 19276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -ENOMEM; 19376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten } 19476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 19576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten export->pwm = pwm; 19676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 19776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten export->child.release = pwm_export_release; 19876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten export->child.parent = parent; 19976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten export->child.devt = MKDEV(0, 0); 2006ca142ad0d1bdf8dd116351b7b9a2bc5670d5271Axel Lin export->child.groups = pwm_groups; 20176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten dev_set_name(&export->child, "pwm%u", pwm->hwpwm); 20276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 20376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = device_register(&export->child); 20476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret) { 20576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten clear_bit(PWMF_EXPORTED, &pwm->flags); 20676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten kfree(export); 20776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 20876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten } 20976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 21076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return 0; 21176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 21276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 21376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic int pwm_unexport_match(struct device *child, void *data) 21476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 21576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return child_to_pwm_device(child) == data; 21676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 21776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 21876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) 21976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 22076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device *child; 22176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 22276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) 22376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -ENODEV; 22476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 22576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten child = device_find_child(parent, pwm, pwm_unexport_match); 22676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (!child) 22776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -ENODEV; 22876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 22976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten /* for device_find_child() */ 23076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten put_device(child); 23176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten device_unregister(child); 23276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten pwm_put(pwm); 23376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 23476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return 0; 23576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 23676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 23776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_export_store(struct device *parent, 23876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 23976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t len) 24076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 24176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_chip *chip = dev_get_drvdata(parent); 24276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_device *pwm; 24376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten unsigned int hwpwm; 24476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 24576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 24676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = kstrtouint(buf, 0, &hwpwm); 24776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret < 0) 24876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 24976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 25076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (hwpwm >= chip->npwm) 25176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -ENODEV; 25276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 25376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten pwm = pwm_request_from_chip(chip, hwpwm, "sysfs"); 25476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (IS_ERR(pwm)) 25576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return PTR_ERR(pwm); 25676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 25776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_export_child(parent, pwm); 25876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret < 0) 25976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten pwm_put(pwm); 26076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 26176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : len; 26276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 2639da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartmanstatic DEVICE_ATTR(export, 0200, NULL, pwm_export_store); 26476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 26576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic ssize_t pwm_unexport_store(struct device *parent, 26676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device_attribute *attr, 26776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const char *buf, size_t len) 26876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 26976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct pwm_chip *chip = dev_get_drvdata(parent); 27076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten unsigned int hwpwm; 27176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten int ret; 27276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 27376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = kstrtouint(buf, 0, &hwpwm); 27476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (ret < 0) 27576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret; 27676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 27776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (hwpwm >= chip->npwm) 27876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return -ENODEV; 27976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 28076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]); 28176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 28276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return ret ? : len; 28376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 2849da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartmanstatic DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store); 28576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 2869da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartmanstatic ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 2879da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman char *buf) 28876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 28976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten const struct pwm_chip *chip = dev_get_drvdata(parent); 29076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 29176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return sprintf(buf, "%u\n", chip->npwm); 29276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 2939da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartmanstatic DEVICE_ATTR_RO(npwm); 29476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 2959da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartmanstatic struct attribute *pwm_chip_attrs[] = { 2969da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman &dev_attr_export.attr, 2979da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman &dev_attr_unexport.attr, 2989da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman &dev_attr_npwm.attr, 2999da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman NULL, 30076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten}; 3019da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-HartmanATTRIBUTE_GROUPS(pwm_chip); 30276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 30376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic struct class pwm_class = { 30476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten .name = "pwm", 30576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten .owner = THIS_MODULE, 3069da01759636f519967c0922ae12bd9fff739db9aGreg Kroah-Hartman .dev_groups = pwm_chip_groups, 30776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten}; 30876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 30976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic int pwmchip_sysfs_match(struct device *parent, const void *data) 31076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 31176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return dev_get_drvdata(parent) == data; 31276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 31376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 31476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenvoid pwmchip_sysfs_export(struct pwm_chip *chip) 31576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 31676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device *parent; 31776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 31876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten /* 31976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * If device_create() fails the pwm_chip is still usable by 32076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten * the kernel its just not exported. 32176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten */ 32276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip, 32376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten "pwmchip%d", chip->base); 32476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (IS_ERR(parent)) { 32576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten dev_warn(chip->dev, 32676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten "device_create failed for pwm_chip sysfs export\n"); 32776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten } 32876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 32976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 33076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenvoid pwmchip_sysfs_unexport(struct pwm_chip *chip) 33176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 33276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten struct device *parent; 33376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 33476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten parent = class_find_device(&pwm_class, NULL, chip, 33576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten pwmchip_sysfs_match); 33676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten if (parent) { 33776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten /* for class_find_device() */ 33876abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten put_device(parent); 33976abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten device_unregister(parent); 34076abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten } 34176abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 34276abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten 34376abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetenstatic int __init pwm_sysfs_init(void) 34476abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten{ 34576abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten return class_register(&pwm_class); 34676abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweeten} 34776abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3dH Hartley Sweetensubsys_initcall(pwm_sysfs_init); 348