18e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash/* 28e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * ECAP PWM driver 38e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * 48e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/ 58e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * 68e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * This program is free software; you can redistribute it and/or modify 78e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * it under the terms of the GNU General Public License as published by 88e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * the Free Software Foundation; either version 2 of the License, or 98e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * (at your option) any later version. 108e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * 118e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * This program is distributed in the hope that it will be useful, 128e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * but WITHOUT ANY WARRANTY; without even the implied warranty of 138e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * GNU General Public License for more details. 158e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * 168e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * You should have received a copy of the GNU General Public License 178e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * along with this program; if not, write to the Free Software 188e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 198e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash */ 208e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 218e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/module.h> 228e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/platform_device.h> 238e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/io.h> 248e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/err.h> 258e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/clk.h> 268e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/pm_runtime.h> 278e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#include <linux/pwm.h> 28333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash#include <linux/of_device.h> 29333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 30333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash#include "pwm-tipwmss.h" 318e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 328e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash/* ECAP registers and bits definitions */ 338e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define CAP1 0x08 348e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define CAP2 0x0C 358e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define CAP3 0x10 368e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define CAP4 0x14 378e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define ECCTL2 0x2A 38454870a44b0687675180506b7774fb559d610675Philip, Avinash#define ECCTL2_APWM_POL_LOW BIT(10) 398e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define ECCTL2_APWM_MODE BIT(9) 408e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) 418e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash#define ECCTL2_TSCTR_FREERUN BIT(4) 428e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 430d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinashstruct ecap_context { 440d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash u32 cap3; 450d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash u32 cap4; 460d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash u16 ecctl2; 470d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash}; 480d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 498e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstruct ecap_pwm_chip { 508e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct pwm_chip chip; 518e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned int clk_rate; 528e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash void __iomem *mmio_base; 530d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash struct ecap_context ctx; 548e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash}; 558e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 568e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip) 578e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 588e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return container_of(chip, struct ecap_pwm_chip, chip); 598e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 608e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 618e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash/* 628e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * period_ns = 10^9 * period_cycles / PWM_CLK_RATE 638e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE 648e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash */ 658e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 668e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash int duty_ns, int period_ns) 678e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 688e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 698e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned long long c; 708e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned long period_cycles, duty_cycles; 718e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned int reg_val; 728e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 73c2d476a98f71c55e9acdca1d5a1080a22c0622afThierry Reding if (period_ns > NSEC_PER_SEC) 748e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return -ERANGE; 758e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 768e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash c = pc->clk_rate; 778e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash c = c * period_ns; 788e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash do_div(c, NSEC_PER_SEC); 798e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash period_cycles = (unsigned long)c; 808e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 818e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (period_cycles < 1) { 828e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash period_cycles = 1; 838e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash duty_cycles = 1; 848e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } else { 858e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash c = pc->clk_rate; 868e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash c = c * duty_ns; 878e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash do_div(c, NSEC_PER_SEC); 888e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash duty_cycles = (unsigned long)c; 898e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 908e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 918e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_get_sync(pc->chip.dev); 928e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 938e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val = readw(pc->mmio_base + ECCTL2); 948e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 958e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* Configure APWM mode & disable sync option */ 968e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA; 978e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 988e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writew(reg_val, pc->mmio_base + ECCTL2); 998e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1008e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (!test_bit(PWMF_ENABLED, &pwm->flags)) { 1018e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* Update active registers if not running */ 1028e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writel(duty_cycles, pc->mmio_base + CAP2); 1038e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writel(period_cycles, pc->mmio_base + CAP1); 1048e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } else { 1058e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* 1068e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * Update shadow registers to configure period and 1078e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * compare values. This helps current PWM period to 1088e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * complete on reconfiguring 1098e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash */ 1108e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writel(duty_cycles, pc->mmio_base + CAP4); 1118e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writel(period_cycles, pc->mmio_base + CAP3); 1128e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 1138e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 114c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash if (!test_bit(PWMF_ENABLED, &pwm->flags)) { 115c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash reg_val = readw(pc->mmio_base + ECCTL2); 116c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash /* Disable APWM mode to put APWM output Low */ 117c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash reg_val &= ~ECCTL2_APWM_MODE; 118c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash writew(reg_val, pc->mmio_base + ECCTL2); 119c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash } 120c06fad9d28c95b024ea10455cf1397432b12848dPhilip, Avinash 1218e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_put_sync(pc->chip.dev); 1228e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return 0; 1238e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 1248e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 125454870a44b0687675180506b7774fb559d610675Philip, Avinashstatic int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, 126454870a44b0687675180506b7774fb559d610675Philip, Avinash enum pwm_polarity polarity) 127454870a44b0687675180506b7774fb559d610675Philip, Avinash{ 128454870a44b0687675180506b7774fb559d610675Philip, Avinash struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 129454870a44b0687675180506b7774fb559d610675Philip, Avinash unsigned short reg_val; 130454870a44b0687675180506b7774fb559d610675Philip, Avinash 131454870a44b0687675180506b7774fb559d610675Philip, Avinash pm_runtime_get_sync(pc->chip.dev); 132454870a44b0687675180506b7774fb559d610675Philip, Avinash reg_val = readw(pc->mmio_base + ECCTL2); 133454870a44b0687675180506b7774fb559d610675Philip, Avinash if (polarity == PWM_POLARITY_INVERSED) 134454870a44b0687675180506b7774fb559d610675Philip, Avinash /* Duty cycle defines LOW period of PWM */ 135454870a44b0687675180506b7774fb559d610675Philip, Avinash reg_val |= ECCTL2_APWM_POL_LOW; 136454870a44b0687675180506b7774fb559d610675Philip, Avinash else 137454870a44b0687675180506b7774fb559d610675Philip, Avinash /* Duty cycle defines HIGH period of PWM */ 138454870a44b0687675180506b7774fb559d610675Philip, Avinash reg_val &= ~ECCTL2_APWM_POL_LOW; 139454870a44b0687675180506b7774fb559d610675Philip, Avinash 140454870a44b0687675180506b7774fb559d610675Philip, Avinash writew(reg_val, pc->mmio_base + ECCTL2); 141454870a44b0687675180506b7774fb559d610675Philip, Avinash pm_runtime_put_sync(pc->chip.dev); 142454870a44b0687675180506b7774fb559d610675Philip, Avinash return 0; 143454870a44b0687675180506b7774fb559d610675Philip, Avinash} 144454870a44b0687675180506b7774fb559d610675Philip, Avinash 1458e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 1468e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 1478e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 1488e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned int reg_val; 1498e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1508e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* Leave clock enabled on enabling PWM */ 1518e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_get_sync(pc->chip.dev); 1528e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1538e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* 1548e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * Enable 'Free run Time stamp counter mode' to start counter 1558e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * and 'APWM mode' to enable APWM output 1568e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash */ 1578e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val = readw(pc->mmio_base + ECCTL2); 1588e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE; 1598e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writew(reg_val, pc->mmio_base + ECCTL2); 1608e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return 0; 1618e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 1628e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1638e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 1648e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 1658e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); 1668e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash unsigned int reg_val; 1678e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1688e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* 1698e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * Disable 'Free run Time stamp counter mode' to stop counter 1708e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash * and 'APWM mode' to put APWM output to low 1718e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash */ 1728e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val = readw(pc->mmio_base + ECCTL2); 1738e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash reg_val &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE); 1748e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash writew(reg_val, pc->mmio_base + ECCTL2); 1758e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1768e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash /* Disable clock on PWM disable */ 1778e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_put_sync(pc->chip.dev); 1788e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 1798e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1808e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 1818e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 1828e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (test_bit(PWMF_ENABLED, &pwm->flags)) { 1838e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash dev_warn(chip->dev, "Removing PWM device without disabling\n"); 1848e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_put_sync(chip->dev); 1858e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 1868e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 1878e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 1888e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic const struct pwm_ops ecap_pwm_ops = { 1898e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .free = ecap_pwm_free, 1908e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .config = ecap_pwm_config, 191454870a44b0687675180506b7774fb559d610675Philip, Avinash .set_polarity = ecap_pwm_set_polarity, 1928e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .enable = ecap_pwm_enable, 1938e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .disable = ecap_pwm_disable, 1948e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .owner = THIS_MODULE, 1958e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash}; 1968e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 197333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinashstatic const struct of_device_id ecap_of_match[] = { 198333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash { .compatible = "ti,am33xx-ecap" }, 199333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash {}, 200333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash}; 201333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, AvinashMODULE_DEVICE_TABLE(of, ecap_of_match); 202333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 2033e9fe83d278cce6974f0a4d1870c0ff4a0b74ba5Bill Pembertonstatic int ecap_pwm_probe(struct platform_device *pdev) 2048e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 2058e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash int ret; 2068e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct resource *r; 2078e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct clk *clk; 2088e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct ecap_pwm_chip *pc; 209333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash u16 status; 2108e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2118e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); 212c10d50631f29a1f09a0f3286e988877bd76733e3Jingoo Han if (!pc) 2138e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return -ENOMEM; 2148e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2158e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash clk = devm_clk_get(&pdev->dev, "fck"); 2168e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (IS_ERR(clk)) { 2178e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash dev_err(&pdev->dev, "failed to get clock\n"); 2188e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return PTR_ERR(clk); 2198e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 2208e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2218e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc->clk_rate = clk_get_rate(clk); 2228e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (!pc->clk_rate) { 2238e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash dev_err(&pdev->dev, "failed to get clock rate\n"); 2248e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return -EINVAL; 2258e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 2268e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2278e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc->chip.dev = &pdev->dev; 2288e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc->chip.ops = &ecap_pwm_ops; 229333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pc->chip.of_xlate = of_pwm_xlate_with_flags; 230333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pc->chip.of_pwm_n_cells = 3; 2318e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc->chip.base = -1; 2328e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pc->chip.npwm = 1; 2338e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2348e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2356d4294d1634543853febc4287ecf02998fd234e1Thierry Reding pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); 2366d4294d1634543853febc4287ecf02998fd234e1Thierry Reding if (IS_ERR(pc->mmio_base)) 2376d4294d1634543853febc4287ecf02998fd234e1Thierry Reding return PTR_ERR(pc->mmio_base); 2388e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2398e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash ret = pwmchip_add(&pc->chip); 2408e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash if (ret < 0) { 2418e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 2428e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return ret; 2438e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash } 2448e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2458e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_enable(&pdev->dev); 246333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_get_sync(&pdev->dev); 247333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 248333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash status = pwmss_submodule_state_change(pdev->dev.parent, 249333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash PWMSS_ECAPCLK_EN); 250333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash if (!(status & PWMSS_ECAPCLK_EN_ACK)) { 251333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); 252333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash ret = -EINVAL; 253333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash goto pwmss_clk_failure; 254333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash } 255333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 256333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_put_sync(&pdev->dev); 257333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 2588e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash platform_set_drvdata(pdev, pc); 2598e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return 0; 260333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 261333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinashpwmss_clk_failure: 262333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_put_sync(&pdev->dev); 263333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_disable(&pdev->dev); 264333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pwmchip_remove(&pc->chip); 265333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash return ret; 2668e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 2678e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 26877f37917a6f2bd8635b553178bb34bdd80f08e40Bill Pembertonstatic int ecap_pwm_remove(struct platform_device *pdev) 2698e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash{ 2708e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); 2718e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 272333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_get_sync(&pdev->dev); 273333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash /* 274333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash * Due to hardware misbehaviour, acknowledge of the stop_req 275333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash * is missing. Hence checking of the status bit skipped. 276333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash */ 277333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ); 278333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash pm_runtime_put_sync(&pdev->dev); 279333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash 2808e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash pm_runtime_disable(&pdev->dev); 2818e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash return pwmchip_remove(&pc->chip); 2828e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash} 2838e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 2843943a650f62d0a88788db30c92df584660f3999dJingoo Han#ifdef CONFIG_PM_SLEEP 285a38c9898574967c5a8ab670f1b27d9ecf71d32ccAxel Linstatic void ecap_pwm_save_context(struct ecap_pwm_chip *pc) 2860d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash{ 2870d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pm_runtime_get_sync(pc->chip.dev); 2880d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2); 2890d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pc->ctx.cap4 = readl(pc->mmio_base + CAP4); 2900d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pc->ctx.cap3 = readl(pc->mmio_base + CAP3); 2910d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pm_runtime_put_sync(pc->chip.dev); 2920d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash} 2930d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 294a38c9898574967c5a8ab670f1b27d9ecf71d32ccAxel Linstatic void ecap_pwm_restore_context(struct ecap_pwm_chip *pc) 2950d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash{ 2960d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash writel(pc->ctx.cap3, pc->mmio_base + CAP3); 2970d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash writel(pc->ctx.cap4, pc->mmio_base + CAP4); 2980d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2); 2990d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash} 3000d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3010d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinashstatic int ecap_pwm_suspend(struct device *dev) 3020d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash{ 3030d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash struct ecap_pwm_chip *pc = dev_get_drvdata(dev); 3040d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash struct pwm_device *pwm = pc->chip.pwms; 3050d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3060d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash ecap_pwm_save_context(pc); 3070d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3080d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash /* Disable explicitly if PWM is running */ 3090d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash if (test_bit(PWMF_ENABLED, &pwm->flags)) 3100d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pm_runtime_put_sync(dev); 3110d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3120d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash return 0; 3130d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash} 3140d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3150d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinashstatic int ecap_pwm_resume(struct device *dev) 3160d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash{ 3170d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash struct ecap_pwm_chip *pc = dev_get_drvdata(dev); 3180d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash struct pwm_device *pwm = pc->chip.pwms; 3190d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3200d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash /* Enable explicitly if PWM was running */ 3210d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash if (test_bit(PWMF_ENABLED, &pwm->flags)) 3220d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash pm_runtime_get_sync(dev); 3230d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3240d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash ecap_pwm_restore_context(pc); 3250d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash return 0; 3260d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash} 327b78f5fc92a836259b69d49129c6c1cad9b03c322Jingoo Han#endif 3280d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3290d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinashstatic SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume); 3300d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash 3318e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashstatic struct platform_driver ecap_pwm_driver = { 3328e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .driver = { 333333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash .name = "ecap", 334333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash .owner = THIS_MODULE, 335333b08ee8c6e120d67118e4eb71c45f5c369c8a4Philip, Avinash .of_match_table = ecap_of_match, 3360d75c203effefa4f62ca4d30bf52bd9ec246717fPhilip Avinash .pm = &ecap_pwm_pm_ops, 3378e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash }, 3388e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash .probe = ecap_pwm_probe, 339fd1091125a1d11fcc635749d0d3dec36904a7a48Bill Pemberton .remove = ecap_pwm_remove, 3408e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash}; 3418e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 3428e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinashmodule_platform_driver(ecap_pwm_driver); 3438e0cb05b3b758885aab09883adf189f8dd8402b2Philip, Avinash 3448e0cb05b3b758885aab09883adf189f8dd8402b2Philip, AvinashMODULE_DESCRIPTION("ECAP PWM driver"); 3458e0cb05b3b758885aab09883adf189f8dd8402b2Philip, AvinashMODULE_AUTHOR("Texas Instruments"); 3468e0cb05b3b758885aab09883adf189f8dd8402b2Philip, AvinashMODULE_LICENSE("GPL"); 347