diff options
Diffstat (limited to 'drivers/pwm/pwm-tipwmss.c')
| -rw-r--r-- | drivers/pwm/pwm-tipwmss.c | 139 | 
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c new file mode 100644 index 00000000000..3448a1c8859 --- /dev/null +++ b/drivers/pwm/pwm-tipwmss.c @@ -0,0 +1,139 @@ +/* + * TI PWM Subsystem driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> +#include <linux/of_device.h> + +#include "pwm-tipwmss.h" + +#define PWMSS_CLKCONFIG		0x8	/* Clock gating reg */ +#define PWMSS_CLKSTATUS		0xc	/* Clock gating status reg */ + +struct pwmss_info { +	void __iomem	*mmio_base; +	struct mutex	pwmss_lock; +	u16		pwmss_clkconfig; +}; + +u16 pwmss_submodule_state_change(struct device *dev, int set) +{ +	struct pwmss_info *info = dev_get_drvdata(dev); +	u16 val; + +	mutex_lock(&info->pwmss_lock); +	val = readw(info->mmio_base + PWMSS_CLKCONFIG); +	val |= set; +	writew(val , info->mmio_base + PWMSS_CLKCONFIG); +	mutex_unlock(&info->pwmss_lock); + +	return readw(info->mmio_base + PWMSS_CLKSTATUS); +} +EXPORT_SYMBOL(pwmss_submodule_state_change); + +static const struct of_device_id pwmss_of_match[] = { +	{ .compatible	= "ti,am33xx-pwmss" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, pwmss_of_match); + +static int pwmss_probe(struct platform_device *pdev) +{ +	int ret; +	struct resource *r; +	struct pwmss_info *info; +	struct device_node *node = pdev->dev.of_node; + +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); +	if (!info) { +		dev_err(&pdev->dev, "failed to allocate memory\n"); +		return -ENOMEM; +	} + +	mutex_init(&info->pwmss_lock); + +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!r) { +		dev_err(&pdev->dev, "no memory resource defined\n"); +		return -ENODEV; +	} + +	info->mmio_base = devm_request_and_ioremap(&pdev->dev, r); +	if (!info->mmio_base) +		return -EADDRNOTAVAIL; + +	pm_runtime_enable(&pdev->dev); +	pm_runtime_get_sync(&pdev->dev); +	platform_set_drvdata(pdev, info); + +	/* Populate all the child nodes here... */ +	ret = of_platform_populate(node, NULL, NULL, &pdev->dev); +	if (ret) +		dev_err(&pdev->dev, "no child node found\n"); + +	return ret; +} + +static int pwmss_remove(struct platform_device *pdev) +{ +	struct pwmss_info *info = platform_get_drvdata(pdev); + +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev); +	mutex_destroy(&info->pwmss_lock); +	return 0; +} + +static int pwmss_suspend(struct device *dev) +{ +	struct pwmss_info *info = dev_get_drvdata(dev); + +	info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG); +	pm_runtime_put_sync(dev); +	return 0; +} + +static int pwmss_resume(struct device *dev) +{ +	struct pwmss_info *info = dev_get_drvdata(dev); + +	pm_runtime_get_sync(dev); +	writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG); +	return 0; +} + +static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); + +static struct platform_driver pwmss_driver = { +	.driver	= { +		.name	= "pwmss", +		.owner	= THIS_MODULE, +		.pm	= &pwmss_pm_ops, +		.of_match_table	= pwmss_of_match, +	}, +	.probe	= pwmss_probe, +	.remove	= pwmss_remove, +}; + +module_platform_driver(pwmss_driver); + +MODULE_DESCRIPTION("PWM Subsystem driver"); +MODULE_AUTHOR("Texas Instruments"); +MODULE_LICENSE("GPL");  |