Commit 38b0a526 authored by Thierry Reding's avatar Thierry Reding

Merge branch 'for-4.11/drivers' into for-next

parents 776906ff 326ed314
...@@ -6,8 +6,8 @@ Required properties: ...@@ -6,8 +6,8 @@ Required properties:
- "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1 - "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1
- "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27 - "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27
- reg: physical base address and length of the controller's registers - reg: physical base address and length of the controller's registers
- #pwm-cells: should be 2. See pwm.txt in this directory for a description of - #pwm-cells: 2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.txt
the cells format. in this directory for a description of the cells format.
- clocks : Clock specifiers for both ipg and per clocks. - clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per" - clock-names : Clock names should include both "ipg" and "per"
See the clock consumer binding, See the clock consumer binding,
...@@ -17,7 +17,7 @@ See the clock consumer binding, ...@@ -17,7 +17,7 @@ See the clock consumer binding,
Example: Example:
pwm1: pwm@53fb4000 { pwm1: pwm@53fb4000 {
#pwm-cells = <2>; #pwm-cells = <3>;
compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; compatible = "fsl,imx53-pwm", "fsl,imx27-pwm";
reg = <0x53fb4000 0x4000>; reg = <0x53fb4000 0x4000>;
clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>,
......
...@@ -76,7 +76,9 @@ config PWM_ATMEL_TCB ...@@ -76,7 +76,9 @@ config PWM_ATMEL_TCB
config PWM_BCM_IPROC config PWM_BCM_IPROC
tristate "iProc PWM support" tristate "iProc PWM support"
depends on ARCH_BCM_IPROC depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on COMMON_CLK
default ARCH_BCM_IPROC
help help
Generic PWM framework driver for Broadcom iProc PWM block. This Generic PWM framework driver for Broadcom iProc PWM block. This
block is used in Broadcom iProc SoC's. block is used in Broadcom iProc SoC's.
......
...@@ -103,7 +103,7 @@ static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -103,7 +103,7 @@ static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
disable_gptimer(priv->pin); disable_gptimer(priv->pin);
} }
static struct pwm_ops bfin_pwm_ops = { static const struct pwm_ops bfin_pwm_ops = {
.request = bfin_pwm_request, .request = bfin_pwm_request,
.free = bfin_pwm_free, .free = bfin_pwm_free,
.config = bfin_pwm_config, .config = bfin_pwm_config,
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define MX3_PWMCR_DOZEEN (1 << 24) #define MX3_PWMCR_DOZEEN (1 << 24)
#define MX3_PWMCR_WAITEN (1 << 23) #define MX3_PWMCR_WAITEN (1 << 23)
#define MX3_PWMCR_DBGEN (1 << 22) #define MX3_PWMCR_DBGEN (1 << 22)
#define MX3_PWMCR_POUTC (1 << 18)
#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16)
#define MX3_PWMCR_CLKSRC_IPG (1 << 16) #define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_SWR (1 << 3) #define MX3_PWMCR_SWR (1 << 3)
...@@ -49,15 +50,10 @@ ...@@ -49,15 +50,10 @@
struct imx_chip { struct imx_chip {
struct clk *clk_per; struct clk *clk_per;
struct clk *clk_ipg;
void __iomem *mmio_base; void __iomem *mmio_base;
struct pwm_chip chip; struct pwm_chip chip;
int (*config)(struct pwm_chip *chip,
struct pwm_device *pwm, int duty_ns, int period_ns);
void (*set_enable)(struct pwm_chip *chip, bool enable);
}; };
#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip)
...@@ -91,176 +87,170 @@ static int imx_pwm_config_v1(struct pwm_chip *chip, ...@@ -91,176 +87,170 @@ static int imx_pwm_config_v1(struct pwm_chip *chip,
return 0; return 0;
} }
static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) static int imx_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
{ {
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
u32 val; u32 val;
int ret;
val = readl(imx->mmio_base + MX1_PWMC); ret = clk_prepare_enable(imx->clk_per);
if (ret < 0)
if (enable) return ret;
val |= MX1_PWMC_EN;
else
val &= ~MX1_PWMC_EN;
val = readl(imx->mmio_base + MX1_PWMC);
val |= MX1_PWMC_EN;
writel(val, imx->mmio_base + MX1_PWMC); writel(val, imx->mmio_base + MX1_PWMC);
}
static int imx_pwm_config_v2(struct pwm_chip *chip,
struct pwm_device *pwm, int duty_ns, int period_ns)
{
struct imx_chip *imx = to_imx_chip(chip);
struct device *dev = chip->dev;
unsigned long long c;
unsigned long period_cycles, duty_cycles, prescale;
unsigned int period_ms;
bool enable = pwm_is_enabled(pwm);
int wait_count = 0, fifoav;
u32 cr, sr;
/*
* i.MX PWMv2 has a 4-word sample FIFO.
* In order to avoid FIFO overflow issue, we do software reset
* to clear all sample FIFO if the controller is disabled or
* wait for a full PWM cycle to get a relinquished FIFO slot
* when the controller is enabled and the FIFO is fully loaded.
*/
if (enable) {
sr = readl(imx->mmio_base + MX3_PWMSR);
fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
NSEC_PER_MSEC);
msleep(period_ms);
sr = readl(imx->mmio_base + MX3_PWMSR);
if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK))
dev_warn(dev, "there is no free FIFO slot\n");
}
} else {
writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
do {
usleep_range(200, 1000);
cr = readl(imx->mmio_base + MX3_PWMCR);
} while ((cr & MX3_PWMCR_SWR) &&
(wait_count++ < MX3_PWM_SWR_LOOP));
if (cr & MX3_PWMCR_SWR)
dev_warn(dev, "software reset timeout\n");
}
c = clk_get_rate(imx->clk_per);
c = c * period_ns;
do_div(c, 1000000000);
period_cycles = c;
prescale = period_cycles / 0x10000 + 1;
period_cycles /= prescale;
c = (unsigned long long)period_cycles * duty_ns;
do_div(c, period_ns);
duty_cycles = c;
/*
* according to imx pwm RM, the real period value should be
* PERIOD value in PWMPR plus 2.
*/
if (period_cycles > 2)
period_cycles -= 2;
else
period_cycles = 0;
writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
writel(period_cycles, imx->mmio_base + MX3_PWMPR);
cr = MX3_PWMCR_PRESCALER(prescale) |
MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
if (enable)
cr |= MX3_PWMCR_EN;
writel(cr, imx->mmio_base + MX3_PWMCR);
return 0; return 0;
} }
static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) static void imx_pwm_disable_v1(struct pwm_chip *chip, struct pwm_device *pwm)
{ {
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
u32 val; u32 val;
val = readl(imx->mmio_base + MX3_PWMCR); val = readl(imx->mmio_base + MX1_PWMC);
val &= ~MX1_PWMC_EN;
if (enable) writel(val, imx->mmio_base + MX1_PWMC);
val |= MX3_PWMCR_EN;
else
val &= ~MX3_PWMCR_EN;
writel(val, imx->mmio_base + MX3_PWMCR); clk_disable_unprepare(imx->clk_per);
} }
static int imx_pwm_config(struct pwm_chip *chip, static void imx_pwm_sw_reset(struct pwm_chip *chip)
struct pwm_device *pwm, int duty_ns, int period_ns)
{ {
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
int ret; struct device *dev = chip->dev;
int wait_count = 0;
ret = clk_prepare_enable(imx->clk_ipg); u32 cr;
if (ret)
return ret; writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR);
do {
usleep_range(200, 1000);
cr = readl(imx->mmio_base + MX3_PWMCR);
} while ((cr & MX3_PWMCR_SWR) &&
(wait_count++ < MX3_PWM_SWR_LOOP));
if (cr & MX3_PWMCR_SWR)
dev_warn(dev, "software reset timeout\n");
}
ret = imx->config(chip, pwm, duty_ns, period_ns); static void imx_pwm_wait_fifo_slot(struct pwm_chip *chip,
struct pwm_device *pwm)
{
struct imx_chip *imx = to_imx_chip(chip);
struct device *dev = chip->dev;
unsigned int period_ms;
int fifoav;
u32 sr;
clk_disable_unprepare(imx->clk_ipg); sr = readl(imx->mmio_base + MX3_PWMSR);
fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
NSEC_PER_MSEC);
msleep(period_ms);
return ret; sr = readl(imx->mmio_base + MX3_PWMSR);
if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK))
dev_warn(dev, "there is no free FIFO slot\n");
}
} }
static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) static int imx_pwm_apply_v2(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{ {
unsigned long period_cycles, duty_cycles, prescale;
struct imx_chip *imx = to_imx_chip(chip); struct imx_chip *imx = to_imx_chip(chip);
struct pwm_state cstate;
unsigned long long c;
int ret; int ret;
u32 cr;
pwm_get_state(pwm, &cstate);
if (state->enabled) {
c = clk_get_rate(imx->clk_per);
c *= state->period;
do_div(c, 1000000000);
period_cycles = c;
prescale = period_cycles / 0x10000 + 1;
period_cycles /= prescale;
c = (unsigned long long)period_cycles * state->duty_cycle;
do_div(c, state->period);
duty_cycles = c;
/*
* according to imx pwm RM, the real period value should be
* PERIOD value in PWMPR plus 2.
*/
if (period_cycles > 2)
period_cycles -= 2;
else
period_cycles = 0;
/*
* Wait for a free FIFO slot if the PWM is already enabled, and
* flush the FIFO if the PWM was disabled and is about to be
* enabled.
*/
if (cstate.enabled) {
imx_pwm_wait_fifo_slot(chip, pwm);
} else {
ret = clk_prepare_enable(imx->clk_per);
if (ret)
return ret;
imx_pwm_sw_reset(chip);
}
ret = clk_prepare_enable(imx->clk_per); writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
if (ret) writel(period_cycles, imx->mmio_base + MX3_PWMPR);
return ret;
imx->set_enable(chip, true); cr = MX3_PWMCR_PRESCALER(prescale) |
MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH |
MX3_PWMCR_EN;
return 0; if (state->polarity == PWM_POLARITY_INVERSED)
} cr |= MX3_PWMCR_POUTC;
static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) writel(cr, imx->mmio_base + MX3_PWMCR);
{ } else if (cstate.enabled) {
struct imx_chip *imx = to_imx_chip(chip); writel(0, imx->mmio_base + MX3_PWMCR);
imx->set_enable(chip, false); clk_disable_unprepare(imx->clk_per);
}
clk_disable_unprepare(imx->clk_per); return 0;
} }
static struct pwm_ops imx_pwm_ops = { static const struct pwm_ops imx_pwm_ops_v1 = {
.enable = imx_pwm_enable, .enable = imx_pwm_enable_v1,
.disable = imx_pwm_disable, .disable = imx_pwm_disable_v1,
.config = imx_pwm_config, .config = imx_pwm_config_v1,
.owner = THIS_MODULE,
};
static const struct pwm_ops imx_pwm_ops_v2 = {
.apply = imx_pwm_apply_v2,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
struct imx_pwm_data { struct imx_pwm_data {
int (*config)(struct pwm_chip *chip, bool polarity_supported;
struct pwm_device *pwm, int duty_ns, int period_ns); const struct pwm_ops *ops;
void (*set_enable)(struct pwm_chip *chip, bool enable);
}; };
static struct imx_pwm_data imx_pwm_data_v1 = { static struct imx_pwm_data imx_pwm_data_v1 = {
.config = imx_pwm_config_v1, .ops = &imx_pwm_ops_v1,
.set_enable = imx_pwm_set_enable_v1,
}; };
static struct imx_pwm_data imx_pwm_data_v2 = { static struct imx_pwm_data imx_pwm_data_v2 = {
.config = imx_pwm_config_v2, .polarity_supported = true,
.set_enable = imx_pwm_set_enable_v2, .ops = &imx_pwm_ops_v2,
}; };
static const struct of_device_id imx_pwm_dt_ids[] = { static const struct of_device_id imx_pwm_dt_ids[] = {
...@@ -282,6 +272,8 @@ static int imx_pwm_probe(struct platform_device *pdev) ...@@ -282,6 +272,8 @@ static int imx_pwm_probe(struct platform_device *pdev)
if (!of_id) if (!of_id)
return -ENODEV; return -ENODEV;
data = of_id->data;
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
if (imx == NULL) if (imx == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -293,27 +285,22 @@ static int imx_pwm_probe(struct platform_device *pdev) ...@@ -293,27 +285,22 @@ static int imx_pwm_probe(struct platform_device *pdev)
return PTR_ERR(imx->clk_per); return PTR_ERR(imx->clk_per);
} }
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); imx->chip.ops = data->ops;
if (IS_ERR(imx->clk_ipg)) {
dev_err(&pdev->dev, "getting ipg clock failed with %ld\n",
PTR_ERR(imx->clk_ipg));
return PTR_ERR(imx->clk_ipg);
}
imx->chip.ops = &imx_pwm_ops;
imx->chip.dev = &pdev->dev; imx->chip.dev = &pdev->dev;
imx->chip.base = -1; imx->chip.base = -1;
imx->chip.npwm = 1; imx->chip.npwm = 1;
if (data->polarity_supported) {
dev_dbg(&pdev->dev, "PWM supports output inversion\n");
imx->chip.of_xlate = of_pwm_xlate_with_flags;
imx->chip.of_pwm_n_cells = 3;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(imx->mmio_base)) if (IS_ERR(imx->mmio_base))
return PTR_ERR(imx->mmio_base); return PTR_ERR(imx->mmio_base);
data = of_id->data;
imx->config = data->config;
imx->set_enable = data->set_enable;
ret = pwmchip_add(&imx->chip); ret = pwmchip_add(&imx->chip);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -17,6 +17,27 @@ ...@@ -17,6 +17,27 @@
#include "pwm-lpss.h" #include "pwm-lpss.h"
/* BayTrail */
static const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
.clk_rate = 25000000,
.npwm = 1,
.base_unit_bits = 16,
};
/* Braswell */
static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
.clk_rate = 19200000,
.npwm = 1,
.base_unit_bits = 16,
};
/* Broxton */
static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
};
static int pwm_lpss_probe_pci(struct pci_dev *pdev, static int pwm_lpss_probe_pci(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -80,6 +101,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = { ...@@ -80,6 +101,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info}, { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info}, { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info}, { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x31c8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info}, { PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info},
{ }, { },
}; };
......
...@@ -18,6 +18,27 @@ ...@@ -18,6 +18,27 @@
#include "pwm-lpss.h" #include "pwm-lpss.h"
/* BayTrail */
static const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
.clk_rate = 25000000,
.npwm = 1,
.base_unit_bits = 16,
};
/* Braswell */
static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
.clk_rate = 19200000,
.npwm = 1,
.base_unit_bits = 16,
};
/* Broxton */
static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
};
static int pwm_lpss_probe_platform(struct platform_device *pdev) static int pwm_lpss_probe_platform(struct platform_device *pdev)
{ {
const struct pwm_lpss_boardinfo *info; const struct pwm_lpss_boardinfo *info;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -37,30 +38,6 @@ struct pwm_lpss_chip { ...@@ -37,30 +38,6 @@ struct pwm_lpss_chip {
const struct pwm_lpss_boardinfo *info; const struct pwm_lpss_boardinfo *info;
}; };
/* BayTrail */
const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
.clk_rate = 25000000,
.npwm = 1,
.base_unit_bits = 16,
};
EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
/* Braswell */
const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
.clk_rate = 19200000,
.npwm = 1,
.base_unit_bits = 16,
};
EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
/* Broxton */
const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
};
EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
{ {
return container_of(chip, struct pwm_lpss_chip, chip); return container_of(chip, struct pwm_lpss_chip, chip);
...@@ -80,17 +57,42 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) ...@@ -80,17 +57,42 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
} }
static void pwm_lpss_update(struct pwm_device *pwm) static int pwm_lpss_update(struct pwm_device *pwm)
{ {
struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
const void __iomem *addr = lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM;
const unsigned int ms = 500 * USEC_PER_MSEC;
u32 val;
int err;
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
/* Give it some time to propagate */
usleep_range(10, 50); /*
* PWM Configuration register has SW_UPDATE bit that is set when a new
* configuration is written to the register. The bit is automatically
* cleared at the start of the next output cycle by the IP block.
*
* If one writes a new configuration to the register while it still has
* the bit enabled, PWM may freeze. That is, while one can still write
* to the register, it won't have an effect. Thus, we try to sleep long
* enough that the bit gets cleared and make sure the bit is not
* enabled while we update the configuration.
*/
err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms);
if (err)
dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n");
return err;
} }