1/* 2 * TI PWM Subsystem driver 3 * 4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 */ 17 18#include <linux/module.h> 19#include <linux/platform_device.h> 20#include <linux/io.h> 21#include <linux/err.h> 22#include <linux/pm_runtime.h> 23#include <linux/of_device.h> 24 25#include "pwm-tipwmss.h" 26 27#define PWMSS_CLKCONFIG 0x8 /* Clock gating reg */ 28#define PWMSS_CLKSTATUS 0xc /* Clock gating status reg */ 29 30struct pwmss_info { 31 void __iomem *mmio_base; 32 struct mutex pwmss_lock; 33 u16 pwmss_clkconfig; 34}; 35 36u16 pwmss_submodule_state_change(struct device *dev, int set) 37{ 38 struct pwmss_info *info = dev_get_drvdata(dev); 39 u16 val; 40 41 mutex_lock(&info->pwmss_lock); 42 val = readw(info->mmio_base + PWMSS_CLKCONFIG); 43 val |= set; 44 writew(val , info->mmio_base + PWMSS_CLKCONFIG); 45 mutex_unlock(&info->pwmss_lock); 46 47 return readw(info->mmio_base + PWMSS_CLKSTATUS); 48} 49EXPORT_SYMBOL(pwmss_submodule_state_change); 50 51static const struct of_device_id pwmss_of_match[] = { 52 { .compatible = "ti,am33xx-pwmss" }, 53 {}, 54}; 55MODULE_DEVICE_TABLE(of, pwmss_of_match); 56 57static int pwmss_probe(struct platform_device *pdev) 58{ 59 int ret; 60 struct resource *r; 61 struct pwmss_info *info; 62 struct device_node *node = pdev->dev.of_node; 63 64 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 65 if (!info) 66 return -ENOMEM; 67 68 mutex_init(&info->pwmss_lock); 69 70 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 71 info->mmio_base = devm_ioremap_resource(&pdev->dev, r); 72 if (IS_ERR(info->mmio_base)) 73 return PTR_ERR(info->mmio_base); 74 75 pm_runtime_enable(&pdev->dev); 76 pm_runtime_get_sync(&pdev->dev); 77 platform_set_drvdata(pdev, info); 78 79 /* Populate all the child nodes here... */ 80 ret = of_platform_populate(node, NULL, NULL, &pdev->dev); 81 if (ret) 82 dev_err(&pdev->dev, "no child node found\n"); 83 84 return ret; 85} 86 87static int pwmss_remove(struct platform_device *pdev) 88{ 89 struct pwmss_info *info = platform_get_drvdata(pdev); 90 91 pm_runtime_put_sync(&pdev->dev); 92 pm_runtime_disable(&pdev->dev); 93 mutex_destroy(&info->pwmss_lock); 94 return 0; 95} 96 97#ifdef CONFIG_PM_SLEEP 98static int pwmss_suspend(struct device *dev) 99{ 100 struct pwmss_info *info = dev_get_drvdata(dev); 101 102 info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG); 103 pm_runtime_put_sync(dev); 104 return 0; 105} 106 107static int pwmss_resume(struct device *dev) 108{ 109 struct pwmss_info *info = dev_get_drvdata(dev); 110 111 pm_runtime_get_sync(dev); 112 writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG); 113 return 0; 114} 115#endif 116 117static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); 118 119static struct platform_driver pwmss_driver = { 120 .driver = { 121 .name = "pwmss", 122 .pm = &pwmss_pm_ops, 123 .of_match_table = pwmss_of_match, 124 }, 125 .probe = pwmss_probe, 126 .remove = pwmss_remove, 127}; 128 129module_platform_driver(pwmss_driver); 130 131MODULE_DESCRIPTION("PWM Subsystem driver"); 132MODULE_AUTHOR("Texas Instruments"); 133MODULE_LICENSE("GPL"); 134