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

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 75840b5..577992d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -224,4 +224,15 @@ 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
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 77a8c18..b1de48b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -20,3 +20,4 @@ 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
diff --git a/drivers/pwm/pwm_test.c b/drivers/pwm/pwm_test.c
new file mode 100644
index 0000000..d9948db
--- /dev/null
+++ b/drivers/pwm/pwm_test.c
@@ -0,0 +1,322 @@
+/*
+ * 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