1166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer/* 2166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * simple driver for PWM (Pulse Width Modulator) controller 3166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * 4166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * This program is free software; you can redistribute it and/or modify 5166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * it under the terms of the GNU General Public License version 2 as 6166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * published by the Free Software Foundation. 7166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * 8166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com> 9166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer */ 10166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 11166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/module.h> 12166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/kernel.h> 13166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/platform_device.h> 145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 15166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/err.h> 16166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/clk.h> 17137fd45ffec15db14034990ceac890975cae7a32Liu Ying#include <linux/delay.h> 18166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/io.h> 19166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer#include <linux/pwm.h> 202a8876cfdf14de557705e2559df99f40058a3b3bSachin Kamat#include <linux/of.h> 21479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel#include <linux/of_device.h> 22c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 23c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig/* i.MX1 and i.MX21 share the same PWM function block: */ 24c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 2540f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMC 0x00 /* PWM Control Register */ 2640f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMS 0x04 /* PWM Sample Register */ 2740f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMP 0x08 /* PWM Period Register */ 28c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 2940f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX1_PWMC_EN (1 << 4) 30c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 31c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ 32c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 3340f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR 0x00 /* PWM Control Register */ 34137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR 0x04 /* PWM Status Register */ 3540f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMSAR 0x0C /* PWM Sample Register */ 3640f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMPR 0x10 /* PWM Period Register */ 3740f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_PRESCALER(x) ((((x) - 1) & 0xFFF) << 4) 3840f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_DOZEEN (1 << 24) 3940f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_WAITEN (1 << 23) 40c0d96aed8c6dd925afe9ea35491a0cd458642a86Jason Chen#define MX3_PWMCR_DBGEN (1 << 22) 4140f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) 4240f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_CLKSRC_IPG (1 << 16) 43137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMCR_SWR (1 << 3) 4440f260c2cebb464dda6916055112963f1421a111Liu Ying#define MX3_PWMCR_EN (1 << 0) 45137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR_FIFOAV_4WORDS 0x4 46137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWMSR_FIFOAV_MASK 0x7 47137fd45ffec15db14034990ceac890975cae7a32Liu Ying 48137fd45ffec15db14034990ceac890975cae7a32Liu Ying#define MX3_PWM_SWR_LOOP 5 49c010dba89bc0f5585550877b1693d11d24063b6bHolger Schurig 5029693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstruct imx_chip { 517b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel struct clk *clk_per; 527b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel struct clk *clk_ipg; 53166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 54166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer void __iomem *mmio_base; 55166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 5629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct pwm_chip chip; 5719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 5819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer int (*config)(struct pwm_chip *chip, 5919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer struct pwm_device *pwm, int duty_ns, int period_ns); 6066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer void (*set_enable)(struct pwm_chip *chip, bool enable); 61166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}; 62166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 6329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) 6429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer 6519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config_v1(struct pwm_chip *chip, 6629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct pwm_device *pwm, int duty_ns, int period_ns) 67166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{ 6829693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct imx_chip *imx = to_imx_chip(chip); 69166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 7019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer /* 7119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * The PWM subsystem allows for exact frequencies. However, 7219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * I cannot connect a scope on my device to the PWM line and 7319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * thus cannot provide the program the PWM controller 7419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * exactly. Instead, I'm relying on the fact that the 7519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * Bootloader (u-boot or WinCE+haret) has programmed the PWM 7619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * function group already. So I'll just modify the PWM sample 7719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * register to follow the ratio of duty_ns vs. period_ns 7819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * accordingly. 7919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * 8019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * This is good enough for programming the brightness of 8119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * the LCD backlight. 8219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * 8319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * The real implementation would divide PERCLK[0] first by 8419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * both the prescaler (/1 .. /128) and then by CLKSEL 8519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * (/2 .. /16). 8619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer */ 8719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer u32 max = readl(imx->mmio_base + MX1_PWMP); 8819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer u32 p = max * duty_ns / period_ns; 8919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer writel(max - p, imx->mmio_base + MX1_PWMS); 9019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 9119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer return 0; 9219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer} 9319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 9466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauerstatic void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) 9566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer{ 9666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer struct imx_chip *imx = to_imx_chip(chip); 9766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer u32 val; 9866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 9966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val = readl(imx->mmio_base + MX1_PWMC); 10066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 10166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer if (enable) 10266ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val |= MX1_PWMC_EN; 10366ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer else 10466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val &= ~MX1_PWMC_EN; 10566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 10666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer writel(val, imx->mmio_base + MX1_PWMC); 10766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer} 10866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 10919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config_v2(struct pwm_chip *chip, 11019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer struct pwm_device *pwm, int duty_ns, int period_ns) 11119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer{ 11219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer struct imx_chip *imx = to_imx_chip(chip); 113137fd45ffec15db14034990ceac890975cae7a32Liu Ying struct device *dev = chip->dev; 11419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer unsigned long long c; 11519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer unsigned long period_cycles, duty_cycles, prescale; 116137fd45ffec15db14034990ceac890975cae7a32Liu Ying unsigned int period_ms; 117137fd45ffec15db14034990ceac890975cae7a32Liu Ying bool enable = test_bit(PWMF_ENABLED, &pwm->flags); 118137fd45ffec15db14034990ceac890975cae7a32Liu Ying int wait_count = 0, fifoav; 119137fd45ffec15db14034990ceac890975cae7a32Liu Ying u32 cr, sr; 120137fd45ffec15db14034990ceac890975cae7a32Liu Ying 121137fd45ffec15db14034990ceac890975cae7a32Liu Ying /* 122137fd45ffec15db14034990ceac890975cae7a32Liu Ying * i.MX PWMv2 has a 4-word sample FIFO. 123137fd45ffec15db14034990ceac890975cae7a32Liu Ying * In order to avoid FIFO overflow issue, we do software reset 124137fd45ffec15db14034990ceac890975cae7a32Liu Ying * to clear all sample FIFO if the controller is disabled or 125137fd45ffec15db14034990ceac890975cae7a32Liu Ying * wait for a full PWM cycle to get a relinquished FIFO slot 126137fd45ffec15db14034990ceac890975cae7a32Liu Ying * when the controller is enabled and the FIFO is fully loaded. 127137fd45ffec15db14034990ceac890975cae7a32Liu Ying */ 128137fd45ffec15db14034990ceac890975cae7a32Liu Ying if (enable) { 129137fd45ffec15db14034990ceac890975cae7a32Liu Ying sr = readl(imx->mmio_base + MX3_PWMSR); 130137fd45ffec15db14034990ceac890975cae7a32Liu Ying fifoav = sr & MX3_PWMSR_FIFOAV_MASK; 131137fd45ffec15db14034990ceac890975cae7a32Liu Ying if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { 132137fd45ffec15db14034990ceac890975cae7a32Liu Ying period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC); 133137fd45ffec15db14034990ceac890975cae7a32Liu Ying msleep(period_ms); 134137fd45ffec15db14034990ceac890975cae7a32Liu Ying 135137fd45ffec15db14034990ceac890975cae7a32Liu Ying sr = readl(imx->mmio_base + MX3_PWMSR); 136137fd45ffec15db14034990ceac890975cae7a32Liu Ying if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) 137137fd45ffec15db14034990ceac890975cae7a32Liu Ying dev_warn(dev, "there is no free FIFO slot\n"); 138137fd45ffec15db14034990ceac890975cae7a32Liu Ying } 139137fd45ffec15db14034990ceac890975cae7a32Liu Ying } else { 140137fd45ffec15db14034990ceac890975cae7a32Liu Ying writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); 141137fd45ffec15db14034990ceac890975cae7a32Liu Ying do { 142137fd45ffec15db14034990ceac890975cae7a32Liu Ying usleep_range(200, 1000); 143137fd45ffec15db14034990ceac890975cae7a32Liu Ying cr = readl(imx->mmio_base + MX3_PWMCR); 144137fd45ffec15db14034990ceac890975cae7a32Liu Ying } while ((cr & MX3_PWMCR_SWR) && 145137fd45ffec15db14034990ceac890975cae7a32Liu Ying (wait_count++ < MX3_PWM_SWR_LOOP)); 146137fd45ffec15db14034990ceac890975cae7a32Liu Ying 147137fd45ffec15db14034990ceac890975cae7a32Liu Ying if (cr & MX3_PWMCR_SWR) 148137fd45ffec15db14034990ceac890975cae7a32Liu Ying dev_warn(dev, "software reset timeout\n"); 149137fd45ffec15db14034990ceac890975cae7a32Liu Ying } 15019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 1517b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel c = clk_get_rate(imx->clk_per); 15219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer c = c * period_ns; 15319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer do_div(c, 1000000000); 15419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer period_cycles = c; 15519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 15619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer prescale = period_cycles / 0x10000 + 1; 15719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 15819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer period_cycles /= prescale; 15919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer c = (unsigned long long)period_cycles * duty_ns; 16019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer do_div(c, period_ns); 16119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer duty_cycles = c; 16219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 16319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer /* 16419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * according to imx pwm RM, the real period value should be 16519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer * PERIOD value in PWMPR plus 2. 16619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer */ 16719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer if (period_cycles > 2) 16819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer period_cycles -= 2; 16919e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer else 17019e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer period_cycles = 0; 17119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 17219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); 17319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer writel(period_cycles, imx->mmio_base + MX3_PWMPR); 17419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 17519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer cr = MX3_PWMCR_PRESCALER(prescale) | 17619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | 1778d1c24bfd20829f5943c76b85c4973db264dd666Sascha Hauer MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; 17866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 179137fd45ffec15db14034990ceac890975cae7a32Liu Ying if (enable) 18066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer cr |= MX3_PWMCR_EN; 18119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 18219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer writel(cr, imx->mmio_base + MX3_PWMCR); 183166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 184166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer return 0; 185166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer} 186166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 18766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauerstatic void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) 18866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer{ 18966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer struct imx_chip *imx = to_imx_chip(chip); 19066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer u32 val; 19166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 19266ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val = readl(imx->mmio_base + MX3_PWMCR); 19366ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 19466ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer if (enable) 19566ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val |= MX3_PWMCR_EN; 19666ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer else 19766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer val &= ~MX3_PWMCR_EN; 19866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 19966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer writel(val, imx->mmio_base + MX3_PWMCR); 20066ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer} 20166ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 20219e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauerstatic int imx_pwm_config(struct pwm_chip *chip, 20319e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer struct pwm_device *pwm, int duty_ns, int period_ns) 20419e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer{ 20519e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer struct imx_chip *imx = to_imx_chip(chip); 2067b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel int ret; 2077b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel 2087b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel ret = clk_prepare_enable(imx->clk_ipg); 2097b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel if (ret) 2107b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel return ret; 21119e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 2127b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel ret = imx->config(chip, pwm, duty_ns, period_ns); 2137b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel 2147b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel clk_disable_unprepare(imx->clk_ipg); 2157b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel 2167b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel return ret; 21719e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer} 21819e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 21929693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 220166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{ 22129693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct imx_chip *imx = to_imx_chip(chip); 222140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer int ret; 223166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 2247b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel ret = clk_prepare_enable(imx->clk_per); 225140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer if (ret) 226140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer return ret; 227140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer 22866ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer imx->set_enable(chip, true); 22966ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer 230140827c148f2f3a95fdcec5310f6cd980139b383Sascha Hauer return 0; 231166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer} 232166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 23329693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 234166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{ 23529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct imx_chip *imx = to_imx_chip(chip); 236166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 23766ad6a613abeeeabc5217a0498fae63205e8ddb8Sascha Hauer imx->set_enable(chip, false); 238166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 2397b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel clk_disable_unprepare(imx->clk_per); 240166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer} 241166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 24229693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic struct pwm_ops imx_pwm_ops = { 24329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer .enable = imx_pwm_enable, 24429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer .disable = imx_pwm_disable, 24529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer .config = imx_pwm_config, 24629693248edf10830db2ef82b36806e378ff75c67Sascha Hauer .owner = THIS_MODULE, 24729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer}; 248166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 249479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstruct imx_pwm_data { 250479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel int (*config)(struct pwm_chip *chip, 251479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel struct pwm_device *pwm, int duty_ns, int period_ns); 252479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel void (*set_enable)(struct pwm_chip *chip, bool enable); 253479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel}; 254479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel 255479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic struct imx_pwm_data imx_pwm_data_v1 = { 256479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel .config = imx_pwm_config_v1, 257479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel .set_enable = imx_pwm_set_enable_v1, 258479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel}; 259479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel 260479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic struct imx_pwm_data imx_pwm_data_v2 = { 261479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel .config = imx_pwm_config_v2, 262479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel .set_enable = imx_pwm_set_enable_v2, 263479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel}; 264479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel 265479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabelstatic const struct of_device_id imx_pwm_dt_ids[] = { 266479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, }, 267479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, 268479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel { /* sentinel */ } 269479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel}; 270479e2e301c626cc64fb27b6b1938655eaba8b036Philipp ZabelMODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); 271479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel 2723e9fe83d278cce6974f0a4d1870c0ff4a0b74ba5Bill Pembertonstatic int imx_pwm_probe(struct platform_device *pdev) 273166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{ 274479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel const struct of_device_id *of_id = 275479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel of_match_device(imx_pwm_dt_ids, &pdev->dev); 276983290b0625628448ea8907243e3cbceda0a8d74Lothar Waßmann const struct imx_pwm_data *data; 27729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct imx_chip *imx; 278166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer struct resource *r; 279166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer int ret = 0; 280166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 281479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel if (!of_id) 282479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel return -ENODEV; 283479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel 284a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); 2851cbec749bf5a7d9259ce0650e2287cf95e65225dJingoo Han if (imx == NULL) 286166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer return -ENOMEM; 287166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 2887b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel imx->clk_per = devm_clk_get(&pdev->dev, "per"); 2897b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel if (IS_ERR(imx->clk_per)) { 2907b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel dev_err(&pdev->dev, "getting per clock failed with %ld\n", 2917b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel PTR_ERR(imx->clk_per)); 2927b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel return PTR_ERR(imx->clk_per); 2937b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel } 294166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 2957b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 2967b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel if (IS_ERR(imx->clk_ipg)) { 2977b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", 2987b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel PTR_ERR(imx->clk_ipg)); 2997b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel return PTR_ERR(imx->clk_ipg); 3007b27c160c68152581c702b9f1fe362338d2a0cadPhilipp Zabel } 301166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 30229693248edf10830db2ef82b36806e378ff75c67Sascha Hauer imx->chip.ops = &imx_pwm_ops; 30329693248edf10830db2ef82b36806e378ff75c67Sascha Hauer imx->chip.dev = &pdev->dev; 30429693248edf10830db2ef82b36806e378ff75c67Sascha Hauer imx->chip.base = -1; 30529693248edf10830db2ef82b36806e378ff75c67Sascha Hauer imx->chip.npwm = 1; 30631c4fa3442570d001f58303dea36d81693bc199cShawn Guo imx->chip.can_sleep = true; 307166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 308166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3096d4294d1634543853febc4287ecf02998fd234e1Thierry Reding imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); 3106d4294d1634543853febc4287ecf02998fd234e1Thierry Reding if (IS_ERR(imx->mmio_base)) 3116d4294d1634543853febc4287ecf02998fd234e1Thierry Reding return PTR_ERR(imx->mmio_base); 312166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 313479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel data = of_id->data; 314479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel imx->config = data->config; 315479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel imx->set_enable = data->set_enable; 31619e73333236a6115617f8ffb4cc290bdb6f2865aSascha Hauer 31729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer ret = pwmchip_add(&imx->chip); 31829693248edf10830db2ef82b36806e378ff75c67Sascha Hauer if (ret < 0) 319a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin return ret; 320166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 32129693248edf10830db2ef82b36806e378ff75c67Sascha Hauer platform_set_drvdata(pdev, imx); 322166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer return 0; 323166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer} 324166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 32577f37917a6f2bd8635b553178bb34bdd80f08e40Bill Pembertonstatic int imx_pwm_remove(struct platform_device *pdev) 326166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer{ 32729693248edf10830db2ef82b36806e378ff75c67Sascha Hauer struct imx_chip *imx; 328166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 32929693248edf10830db2ef82b36806e378ff75c67Sascha Hauer imx = platform_get_drvdata(pdev); 33029693248edf10830db2ef82b36806e378ff75c67Sascha Hauer if (imx == NULL) 331166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer return -ENODEV; 332166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 333a9970e3becbbb095296afdf0bcaa1ce2b819360fAxel Lin return pwmchip_remove(&imx->chip); 334166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer} 335166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 33629693248edf10830db2ef82b36806e378ff75c67Sascha Hauerstatic struct platform_driver imx_pwm_driver = { 337166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer .driver = { 338479e2e301c626cc64fb27b6b1938655eaba8b036Philipp Zabel .name = "imx-pwm", 3393dd0a909479c1d372341d749b4ff94cd638b57daThierry Reding .owner = THIS_MODULE, 340becbca1390a5147b363a34e238e74cffe65eecc3Sachin Kamat .of_match_table = imx_pwm_dt_ids, 341166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer }, 34229693248edf10830db2ef82b36806e378ff75c67Sascha Hauer .probe = imx_pwm_probe, 343fd1091125a1d11fcc635749d0d3dec36904a7a48Bill Pemberton .remove = imx_pwm_remove, 344166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer}; 345166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 346208d038f4792b5ca0dc76deebbc0ae13b4f1a744Sascha Hauermodule_platform_driver(imx_pwm_driver); 347166091b1894df3de736f43c649f2e6639f4a31acSascha Hauer 348166091b1894df3de736f43c649f2e6639f4a31acSascha HauerMODULE_LICENSE("GPL v2"); 349166091b1894df3de736f43c649f2e6639f4a31acSascha HauerMODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 350