From edc222f2be0f36583ff9e8c4551e364c27584bdf Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" <avinashphilip@ti.com> Date: Tue, 17 Jul 2012 21:35:11 +0530 Subject: [PATCH 18/51] pwm: pwm_test: Driver support for PWM module testing Signed-off-by: Philip, Avinash <avinashphilip@ti.com> --- drivers/pwm/Kconfig | 11 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm_test.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 drivers/pwm/pwm_test.c @ drivers/pwm/Kconfig:227 @ config PWM_VT8500 To compile this driver as a module, choose M here: the module will be called pwm-vt8500. +config EHRPWM_TEST + tristate "EHRPWM TEST support" + depends on PWM_TIEHRPWM + + help + Test driver support for the EHRPWM PWM driver found on AM33XX + TI SOC + + To compile this driver as a module, choose M here: the module + will be called pwm_ehrpwm. + endif @ drivers/pwm/Makefile:23 @ obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o +obj-$(CONFIG_EHRPWM_TEST) += pwm_test.o @ drivers/pwm/pwm_test.c:4 @ -- +/* + * PWM Test driver + * + * Copyright (C) 2012 Texas Instruments. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> + +struct pwm_test { + struct pwm_device *pwm; + int ret; + struct class *pwm_test_class; + unsigned long period, duty, run, polarity, config, requested; + unsigned long period_s, duty_s, run_s, polarity_s, config_s, requested_s; + struct device *dev; +}; + +static ssize_t pwm_test_show_duty(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + return sprintf(buf, "%lu\n", pwm_test->duty); +} + +static ssize_t pwm_test_store_duty(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 0, &pwm_test->duty_s); + if (rc) + return rc; + return count; +} + +static ssize_t pwm_test_show_period(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + return sprintf(buf, "%lu\n", pwm_test->period); +} + +static ssize_t pwm_test_store_period(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 0, &pwm_test->period_s); + if (rc) + return rc; + + return count; +} + +static ssize_t pwm_test_show_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + if (pwm_test->config) + return sprintf(buf, "config Done\n"); + else + return sprintf(buf, "config Failed\n"); +} +static ssize_t pwm_test_store_config(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + int ret; + + if (pwm_test->duty_s == 0) { + ret = pwm_config(pwm_test->pwm, 0, pwm_test->period_s); + if (ret) { + pwm_test->config = 0; + pr_err("operation failed %d\n", ret); + pwm_test->duty_s = pwm_test->duty; + pwm_test->period_s = pwm_test->period; + return ret; + } + pwm_test->duty = pwm_test->duty_s; + pwm_test->period = pwm_test->period_s; + pwm_test->config = 1; + } else { + ret = pwm_config(pwm_test->pwm, pwm_test->duty_s, + pwm_test->period_s); + if (ret) { + pwm_test->config = 0; + pr_err("operation failed %d\n", ret); + pwm_test->duty_s = pwm_test->duty; + pwm_test->period_s = pwm_test->period; + return ret; + } + pwm_test->duty = pwm_test->duty_s; + pwm_test->period = pwm_test->period_s; + pwm_test->config = 1; + } + return count; +} + +static ssize_t pwm_test_show_run(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", pwm_test->run ? "Enabled" : "Disabled"); +} + +static ssize_t pwm_test_store_run(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 0, &pwm_test->run_s); + if (rc) + return rc; + + if (pwm_test->run_s) + rc = pwm_enable(pwm_test->pwm); + else + pwm_disable(pwm_test->pwm); + + if (rc) { + pr_err("operation failed %d\n", rc); + pwm_test->run_s = pwm_test->run; + return rc; + } + + pwm_test->run = pwm_test->run_s; + return count; +} + +static ssize_t pwm_test_show_polarity(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", + pwm_test->polarity ? "Polarity Inversed" : + "Polarity Normal"); +} + +static ssize_t pwm_test_store_polarity(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 0, &pwm_test->polarity_s); + if (rc) + return rc; + + rc = pwm_set_polarity(pwm_test->pwm, pwm_test->polarity_s); + if (rc) { + pr_err("operation failed %d\n", rc); + return rc; + } + + pwm_test->polarity = pwm_test->polarity_s; + return count; +} + +static ssize_t pwm_test_show_request(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_test *pwm_test = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", pwm_test->requested ? "Requested" : "Freed"); +} + +static ssize_t pwm_test_store_request(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct pwm_test *pwm_test = dev_get_drvdata(dev); + + rc = kstrtoul(buf, 0, &pwm_test->requested_s); + if (rc) + return rc; + + if (pwm_test->requested_s) { + pwm_test->pwm = pwm_get(dev, NULL); + + if (IS_ERR(pwm_test->pwm)) { + dev_err(dev, "%s() %d %ld\n", __func__, __LINE__, + PTR_ERR(pwm_test->pwm)); + rc = -EINVAL; + } + } else { + pwm_free(pwm_test->pwm); + pwm_test->polarity = 0; + pwm_test->run = 0; + pwm_test->duty = 0; + pwm_test->period = 0; + pwm_test->config = 0; + pwm_test->polarity_s = 0; + pwm_test->run_s = 0; + pwm_test->duty_s = 0; + pwm_test->period_s = 0; + pwm_test->config_s = 0; + rc = 0; + } + + if (rc) { + pr_err("operation failed %d\n", rc); + pwm_test->requested_s = pwm_test->requested; + return rc; + } + + pwm_test->requested = pwm_test->requested_s; + return count; +} + +static DEVICE_ATTR(duty, 0644, pwm_test_show_duty, pwm_test_store_duty); +static DEVICE_ATTR(period, 0644, pwm_test_show_period, pwm_test_store_period); +static DEVICE_ATTR(polarity, 0644, pwm_test_show_polarity, + pwm_test_store_polarity); +static DEVICE_ATTR(config, 0644 , pwm_test_show_config, pwm_test_store_config); +static DEVICE_ATTR(run, 0644 , pwm_test_show_run, pwm_test_store_run); +static DEVICE_ATTR(request, 0644 , pwm_test_show_request, pwm_test_store_request); + +static const struct attribute *pwm_attrs[] = { + &dev_attr_duty.attr, + &dev_attr_period.attr, + &dev_attr_config.attr, + &dev_attr_run.attr, + &dev_attr_request.attr, + &dev_attr_polarity.attr, + NULL, +}; + +static const struct attribute_group pwm_device_attr_group = { + .attrs = (struct attribute **) pwm_attrs, +}; + +static int __init pwm_test_class_init(struct device *dev) +{ + if (sysfs_create_group(&dev->kobj, &pwm_device_attr_group)) + return 1; + return 0; +} + +static int pwm_test_probe(struct platform_device *pdev) +{ + struct pwm_test *pwm_test; + + pwm_test = devm_kzalloc(&pdev->dev, sizeof(*pwm_test), GFP_KERNEL); + + if (!pwm_test) { + dev_err(&pdev->dev, "memory error\n"); + return -ENOMEM; + } + + if (pwm_test_class_init(&pdev->dev)) { + dev_err(&pdev->dev, "sysfs creation failed\n"); + return -EINVAL; + } + dev_set_drvdata(&pdev->dev, pwm_test); + platform_set_drvdata(pdev, pwm_test); + return 0; +} + +static int pwm_test_remove(struct platform_device *pdev) +{ + struct pwm_test *pwm_test = platform_get_drvdata(pdev); + + if (!pwm_test->ret) { + pwm_config(pwm_test->pwm, 0, 0x1000); + pwm_disable(pwm_test->pwm); + pr_emerg("PWM Device Disabled %s\n", dev_name(&pdev->dev)); + } + if (pwm_test->requested) + pwm_free(pwm_test->pwm); + + pr_emerg("PWM Device Freed %s\n", dev_name(&pdev->dev)); + pwm_test->run = 0; + sysfs_remove_group(&pdev->dev.kobj, &pwm_device_attr_group); + return 0; +} + +static struct of_device_id pwm_test_of_match[] = { + { .compatible = "pwm_test" }, + { } +}; + +MODULE_DEVICE_TABLE(of, pwm_test_of_match); + +static struct platform_driver pwm_test_driver = { + .driver = { + .name = "pwm_test", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pwm_test_of_match), + }, + .probe = pwm_test_probe, + .remove = pwm_test_remove, +}; + +module_platform_driver(pwm_test_driver); + +MODULE_DESCRIPTION("pwm_test Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pwm_test"); 1.7.10.4