提交 545b2820 编写于 作者: L Linus Torvalds

Merge tag 'pwm/for-4.11-rc1' of...

Merge tag 'pwm/for-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "This set contains mostly fixes to existing drivers as well as cleanup
  of code that's not been in active use for a while"

* tag 'pwm/for-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (27 commits)
  acpi: lpss: call pwm_add_table() for BSW PWM device
  pwm: Try to load modules during pwm_get()
  pwm: Don't hold pwm_lookup_lock longer than necessary
  pwm: Make the PWM_POLARITY flag in DTB optional
  pwm: Print error messages with pr_err() instead of pr_debug()
  pwm: imx: Add polarity inversion support to i.MX's PWMv2
  pwm: imx: doc: Update imx-pwm.txt documentation entry
  pwm: imx: Remove redundant i.MX PWMv2 code
  pwm: imx: Provide atomic PWM support for i.MX PWMv2
  pwm: imx: Move PWMv2 wait for fifo slot code to a separate function
  pwm: imx: Move PWMv2 software reset code to a separate function
  pwm: imx: Rewrite v1 code to facilitate switch to atomic PWM
  pwm: imx: Add separate set of PWM ops for v1 and v2
  pwm: imx: Remove ipg clock and enable per clock when required
  pwm: lpss: Add Intel Gemini Lake PCI ID
  pwm: lpss: Do not export board infos for different PWM types
  pwm: lpss: Avoid reconfiguring while UPDATE bit is still enabled
  pwm: lpss: Switch to new atomic API
  pwm: lpss: Allow duty cycle to be 0
  pwm: lpss: Avoid potential overflow of base_unit
  ...
...@@ -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>,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/platform_data/x86/pmc_atom.h> #include <linux/platform_data/x86/pmc_atom.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "internal.h" #include "internal.h"
...@@ -154,6 +155,18 @@ static void byt_i2c_setup(struct lpss_private_data *pdata) ...@@ -154,6 +155,18 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
writel(0, pdata->mmio_base + LPSS_I2C_ENABLE); writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
} }
/* BSW PWM used for backlight control by the i915 driver */
static struct pwm_lookup bsw_pwm_lookup[] = {
PWM_LOOKUP_WITH_MODULE("80862288:00", 0, "0000:00:02.0",
"pwm_backlight", 0, PWM_POLARITY_NORMAL,
"pwm-lpss-platform"),
};
static void bsw_pwm_setup(struct lpss_private_data *pdata)
{
pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup));
}
static const struct lpss_device_desc lpt_dev_desc = { static const struct lpss_device_desc lpt_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR, .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
.prv_offset = 0x800, .prv_offset = 0x800,
...@@ -191,6 +204,7 @@ static const struct lpss_device_desc byt_pwm_dev_desc = { ...@@ -191,6 +204,7 @@ static const struct lpss_device_desc byt_pwm_dev_desc = {
static const struct lpss_device_desc bsw_pwm_dev_desc = { static const struct lpss_device_desc bsw_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, .flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.setup = bsw_pwm_setup,
}; };
static const struct lpss_device_desc byt_uart_dev_desc = { static const struct lpss_device_desc byt_uart_dev_desc = {
......
...@@ -29,7 +29,6 @@ struct led_pwm_data { ...@@ -29,7 +29,6 @@ struct led_pwm_data {
unsigned int active_low; unsigned int active_low;
unsigned int period; unsigned int period;
int duty; int duty;
bool can_sleep;
}; };
struct led_pwm_priv { struct led_pwm_priv {
...@@ -49,8 +48,8 @@ static void __led_pwm_set(struct led_pwm_data *led_dat) ...@@ -49,8 +48,8 @@ static void __led_pwm_set(struct led_pwm_data *led_dat)
pwm_enable(led_dat->pwm); pwm_enable(led_dat->pwm);
} }
static void led_pwm_set(struct led_classdev *led_cdev, static int led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness) enum led_brightness brightness)
{ {
struct led_pwm_data *led_dat = struct led_pwm_data *led_dat =
container_of(led_cdev, struct led_pwm_data, cdev); container_of(led_cdev, struct led_pwm_data, cdev);
...@@ -66,12 +65,7 @@ static void led_pwm_set(struct led_classdev *led_cdev, ...@@ -66,12 +65,7 @@ static void led_pwm_set(struct led_classdev *led_cdev,
led_dat->duty = duty; led_dat->duty = duty;
__led_pwm_set(led_dat); __led_pwm_set(led_dat);
}
static int led_pwm_set_blocking(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
led_pwm_set(led_cdev, brightness);
return 0; return 0;
} }
...@@ -112,11 +106,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, ...@@ -112,11 +106,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
return ret; return ret;
} }
led_data->can_sleep = pwm_can_sleep(led_data->pwm); led_data->cdev.brightness_set_blocking = led_pwm_set;
if (!led_data->can_sleep)
led_data->cdev.brightness_set = led_pwm_set;
else
led_data->cdev.brightness_set_blocking = led_pwm_set_blocking;
/* /*
* FIXME: pwm_apply_args() should be removed when switching to the * FIXME: pwm_apply_args() should be removed when switching to the
......
...@@ -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.
......
...@@ -137,9 +137,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) ...@@ -137,9 +137,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
{ {
struct pwm_device *pwm; struct pwm_device *pwm;
/* check, whether the driver supports a third cell for flags */
if (pc->of_pwm_n_cells < 3) if (pc->of_pwm_n_cells < 3)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/* flags in the third cell are optional */
if (args->args_count < 2)
return ERR_PTR(-EINVAL);
if (args->args[0] >= pc->npwm) if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -148,11 +153,10 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) ...@@ -148,11 +153,10 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
return pwm; return pwm;
pwm->args.period = args->args[1]; pwm->args.period = args->args[1];
pwm->args.polarity = PWM_POLARITY_NORMAL;
if (args->args[2] & PWM_POLARITY_INVERTED) if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
pwm->args.polarity = PWM_POLARITY_INVERSED; pwm->args.polarity = PWM_POLARITY_INVERSED;
else
pwm->args.polarity = PWM_POLARITY_NORMAL;
return pwm; return pwm;
} }
...@@ -163,9 +167,14 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) ...@@ -163,9 +167,14 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
{ {
struct pwm_device *pwm; struct pwm_device *pwm;
/* sanity check driver support */
if (pc->of_pwm_n_cells < 2) if (pc->of_pwm_n_cells < 2)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/* all cells are required */
if (args->args_count != pc->of_pwm_n_cells)
return ERR_PTR(-EINVAL);
if (args->args[0] >= pc->npwm) if (args->args[0] >= pc->npwm)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -663,24 +672,17 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) ...@@ -663,24 +672,17 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index, err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
&args); &args);
if (err) { if (err) {
pr_debug("%s(): can't parse \"pwms\" property\n", __func__); pr_err("%s(): can't parse \"pwms\" property\n", __func__);
return ERR_PTR(err); return ERR_PTR(err);
} }
pc = of_node_to_pwmchip(args.np); pc = of_node_to_pwmchip(args.np);
if (IS_ERR(pc)) { if (IS_ERR(pc)) {
pr_debug("%s(): PWM chip not found\n", __func__); pr_err("%s(): PWM chip not found\n", __func__);
pwm = ERR_CAST(pc); pwm = ERR_CAST(pc);
goto put; goto put;
} }
if (args.args_count != pc->of_pwm_n_cells) {
pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
args.np->full_name);
pwm = ERR_PTR(-EINVAL);
goto put;
}
pwm = pc->of_xlate(pc, &args); pwm = pc->of_xlate(pc, &args);
if (IS_ERR(pwm)) if (IS_ERR(pwm))
goto put; goto put;
...@@ -757,12 +759,13 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num) ...@@ -757,12 +759,13 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
*/ */
struct pwm_device *pwm_get(struct device *dev, const char *con_id) struct pwm_device *pwm_get(struct device *dev, const char *con_id)
{ {
struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
const char *dev_id = dev ? dev_name(dev) : NULL; const char *dev_id = dev ? dev_name(dev) : NULL;
struct pwm_chip *chip = NULL; struct pwm_device *pwm;
struct pwm_chip *chip;
unsigned int best = 0; unsigned int best = 0;
struct pwm_lookup *p, *chosen = NULL; struct pwm_lookup *p, *chosen = NULL;
unsigned int match; unsigned int match;
int err;
/* look up via DT first */ /* look up via DT first */
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
...@@ -817,24 +820,35 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) ...@@ -817,24 +820,35 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
} }
} }
if (!chosen) { mutex_unlock(&pwm_lookup_lock);
pwm = ERR_PTR(-ENODEV);
goto out; if (!chosen)
} return ERR_PTR(-ENODEV);
chip = pwmchip_find_by_name(chosen->provider); chip = pwmchip_find_by_name(chosen->provider);
/*
* If the lookup entry specifies a module, load the module and retry
* the PWM chip lookup. This can be used to work around driver load
* ordering issues if driver's can't be made to properly support the
* deferred probe mechanism.
*/
if (!chip && chosen->module) {
err = request_module(chosen->module);
if (err == 0)
chip = pwmchip_find_by_name(chosen->provider);
}
if (!chip) if (!chip)
goto out; return ERR_PTR(-EPROBE_DEFER);
pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id); pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id);
if (IS_ERR(pwm)) if (IS_ERR(pwm))
goto out; return pwm;
pwm->args.period = chosen->period; pwm->args.period = chosen->period;
pwm->args.polarity = chosen->polarity; pwm->args.polarity = chosen->polarity;
out:
mutex_unlock(&pwm_lookup_lock);
return pwm; return pwm;
} }
EXPORT_SYMBOL_GPL(pwm_get); EXPORT_SYMBOL_GPL(pwm_get);
...@@ -960,18 +974,6 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm) ...@@ -960,18 +974,6 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
} }
EXPORT_SYMBOL_GPL(devm_pwm_put); EXPORT_SYMBOL_GPL(devm_pwm_put);
/**
* pwm_can_sleep() - report whether PWM access will sleep
* @pwm: PWM device
*
* Returns: True if accessing the PWM can sleep, false otherwise.
*/
bool pwm_can_sleep(struct pwm_device *pwm)
{
return true;
}
EXPORT_SYMBOL_GPL(pwm_can_sleep);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
{ {
......
...@@ -270,7 +270,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) ...@@ -270,7 +270,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
chip->chip.npwm = 1; chip->chip.npwm = 1;
chip->chip.of_xlate = of_pwm_xlate_with_flags; chip->chip.of_xlate = of_pwm_xlate_with_flags;
chip->chip.of_pwm_n_cells = 3; chip->chip.of_pwm_n_cells = 3;
chip->chip.can_sleep = 1;
ret = pwmchip_add_with_polarity(&chip->chip, PWM_POLARITY_INVERSED); ret = pwmchip_add_with_polarity(&chip->chip, PWM_POLARITY_INVERSED);
if (ret) { if (ret) {
......
...@@ -385,7 +385,6 @@ static int atmel_pwm_probe(struct platform_device *pdev) ...@@ -385,7 +385,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)
atmel_pwm->chip.base = -1; atmel_pwm->chip.base = -1;
atmel_pwm->chip.npwm = 4; atmel_pwm->chip.npwm = 4;
atmel_pwm->chip.can_sleep = true;
atmel_pwm->config = data->config; atmel_pwm->config = data->config;
atmel_pwm->updated_pwms = 0; atmel_pwm->updated_pwms = 0;
mutex_init(&atmel_pwm->isr_lock); mutex_init(&atmel_pwm->isr_lock);
......
...@@ -276,7 +276,6 @@ static int kona_pwmc_probe(struct platform_device *pdev) ...@@ -276,7 +276,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
kp->chip.npwm = 6; kp->chip.npwm = 6;
kp->chip.of_xlate = of_pwm_xlate_with_flags; kp->chip.of_xlate = of_pwm_xlate_with_flags;
kp->chip.of_pwm_n_cells = 3; kp->chip.of_pwm_n_cells = 3;
kp->chip.can_sleep = true;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
kp->base = devm_ioremap_resource(&pdev->dev, res); kp->base = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -206,7 +206,6 @@ static int berlin_pwm_probe(struct platform_device *pdev) ...@@ -206,7 +206,6 @@ static int berlin_pwm_probe(struct platform_device *pdev)
pwm->chip.ops = &berlin_pwm_ops; pwm->chip.ops = &berlin_pwm_ops;
pwm->chip.base = -1; pwm->chip.base = -1;
pwm->chip.npwm = 4; pwm->chip.npwm = 4;
pwm->chip.can_sleep = true;
pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_xlate = of_pwm_xlate_with_flags;
pwm->chip.of_pwm_n_cells = 3; pwm->chip.of_pwm_n_cells = 3;
......
...@@ -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,
......
...@@ -270,7 +270,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) ...@@ -270,7 +270,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
p->chip.ops = &brcmstb_pwm_ops; p->chip.ops = &brcmstb_pwm_ops;
p->chip.base = -1; p->chip.base = -1;
p->chip.npwm = 2; p->chip.npwm = 2;
p->chip.can_sleep = true;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
p->base = devm_ioremap_resource(&pdev->dev, res); p->base = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -446,7 +446,6 @@ static int fsl_pwm_probe(struct platform_device *pdev) ...@@ -446,7 +446,6 @@ static int fsl_pwm_probe(struct platform_device *pdev)
fpc->chip.of_pwm_n_cells = 3; fpc->chip.of_pwm_n_cells = 3;
fpc->chip.base = -1; fpc->chip.base = -1;
fpc->chip.npwm = 8; fpc->chip.npwm = 8;
fpc->chip.can_sleep = true;
ret = pwmchip_add(&fpc->chip); ret = pwmchip_add(&fpc->chip);
if (ret < 0) { if (ret < 0) {
......
...@@ -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,28 +285,22 @@ static int imx_pwm_probe(struct platform_device *pdev) ...@@ -293,28 +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;
imx->chip.can_sleep = true;
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;
......
...@@ -278,7 +278,6 @@ static int lp3943_pwm_probe(struct platform_device *pdev) ...@@ -278,7 +278,6 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
lp3943_pwm->chip.dev = &pdev->dev; lp3943_pwm->chip.dev = &pdev->dev;
lp3943_pwm->chip.ops = &lp3943_pwm_ops; lp3943_pwm->chip.ops = &lp3943_pwm_ops;
lp3943_pwm->chip.npwm = LP3943_NUM_PWMS; lp3943_pwm->chip.npwm = LP3943_NUM_PWMS;
lp3943_pwm->chip.can_sleep = true;
platform_set_drvdata(pdev, lp3943_pwm); platform_set_drvdata(pdev, lp3943_pwm);
......
...@@ -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;
} }
static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
int duty_ns, int period_ns) {
return (pwm_lpss_read(pwm) & PWM_SW_UPDATE) ? -EBUSY : 0;
}
static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
int duty_ns, int period_ns)
{ {
struct pwm_lpss_chip *lpwm = to_lpwm(chip);
unsigned long long on_time_div; unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range; unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC; unsigned long long base_unit, freq = NSEC_PER_SEC;
...@@ -102,62 +104,62 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -102,62 +104,62 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
* The equation is: * The equation is:
* base_unit = round(base_unit_range * freq / c) * base_unit = round(base_unit_range * freq / c)
*/ */
base_unit_range = BIT(lpwm->info->base_unit_bits); base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
freq *= base_unit_range; freq *= base_unit_range;
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c); base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
if (duty_ns <= 0)
duty_ns = 1;
on_time_div = 255ULL * duty_ns; on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns); do_div(on_time_div, period_ns);
on_time_div = 255ULL - on_time_div; on_time_div = 255ULL - on_time_div;
pm_runtime_get_sync(chip->dev);
ctrl = pwm_lpss_read(pwm); ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK; ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT); ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
base_unit &= (base_unit_range - 1); base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div; ctrl |= on_time_div;
pwm_lpss_write(pwm, ctrl); pwm_lpss_write(pwm, ctrl);
/*
* If the PWM is already enabled we need to notify the hardware
* about the change by setting PWM_SW_UPDATE.
*/
if (pwm_is_enabled(pwm))
pwm_lpss_update(pwm);
pm_runtime_put(chip->dev);
return 0;
} }
static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{ {
pm_runtime_get_sync(chip->dev); struct pwm_lpss_chip *lpwm = to_lpwm(chip);
int ret;
/* if (state->enabled) {
* Hardware must first see PWM_SW_UPDATE before the PWM can be if (!pwm_is_enabled(pwm)) {
* enabled. pm_runtime_get_sync(chip->dev);
*/ ret = pwm_lpss_is_updating(pwm);
pwm_lpss_update(pwm); if (ret) {
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); pm_runtime_put(chip->dev);
return 0; return ret;
} }
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
ret = pwm_lpss_update(pwm);
if (ret) {
pm_runtime_put(chip->dev);
return ret;
}
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
} else {
ret = pwm_lpss_is_updating(pwm);
if (ret)
return ret;
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
return pwm_lpss_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
pm_runtime_put(chip->dev);
}
static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) return 0;
{
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
pm_runtime_put(chip->dev);
} }
static const struct pwm_ops pwm_lpss_ops = { static const struct pwm_ops pwm_lpss_ops = {
.config = pwm_lpss_config, .apply = pwm_lpss_apply,
.enable = pwm_lpss_enable,
.disable = pwm_lpss_disable,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -24,10 +24,6 @@ struct pwm_lpss_boardinfo { ...@@ -24,10 +24,6 @@ struct pwm_lpss_boardinfo {
unsigned long base_unit_bits; unsigned long base_unit_bits;
}; };
extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;
extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info;
extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info;
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info); const struct pwm_lpss_boardinfo *info);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
......
...@@ -151,7 +151,7 @@ static int mxs_pwm_probe(struct platform_device *pdev) ...@@ -151,7 +151,7 @@ static int mxs_pwm_probe(struct platform_device *pdev)
mxs->chip.dev = &pdev->dev; mxs->chip.dev = &pdev->dev;
mxs->chip.ops = &mxs_pwm_ops; mxs->chip.ops = &mxs_pwm_ops;
mxs->chip.base = -1; mxs->chip.base = -1;
mxs->chip.can_sleep = true;
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret); dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
......
...@@ -20,8 +20,10 @@ ...@@ -20,8 +20,10 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/pwm.h> #include <linux/pwm.h>
...@@ -65,7 +67,6 @@ ...@@ -65,7 +67,6 @@
#define PCA9685_MAXCHAN 0x10 #define PCA9685_MAXCHAN 0x10
#define LED_FULL (1 << 4) #define LED_FULL (1 << 4)
#define MODE1_RESTART (1 << 7)
#define MODE1_SLEEP (1 << 4) #define MODE1_SLEEP (1 << 4)
#define MODE2_INVRT (1 << 4) #define MODE2_INVRT (1 << 4)
#define MODE2_OUTDRV (1 << 2) #define MODE2_OUTDRV (1 << 2)
...@@ -81,6 +82,10 @@ struct pca9685 { ...@@ -81,6 +82,10 @@ struct pca9685 {
int active_cnt; int active_cnt;
int duty_ns; int duty_ns;
int period_ns; int period_ns;
#if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
struct gpio_chip gpio;
#endif
}; };
static inline struct pca9685 *to_pca(struct pwm_chip *chip) static inline struct pca9685 *to_pca(struct pwm_chip *chip)
...@@ -88,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip) ...@@ -88,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip); return container_of(chip, struct pca9685, chip);
} }
#if IS_ENABLED(CONFIG_GPIOLIB)
static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
{
struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm;
mutex_lock(&pca->lock);
pwm = &pca->chip.pwms[offset];
if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
mutex_unlock(&pca->lock);
return -EBUSY;
}
pwm_set_chip_data(pwm, (void *)1);
mutex_unlock(&pca->lock);
return 0;
}
static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
{
struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm;
mutex_lock(&pca->lock);
pwm = &pca->chip.pwms[offset];
pwm_set_chip_data(pwm, NULL);
mutex_unlock(&pca->lock);
}
static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
{
bool is_gpio = false;
mutex_lock(&pca->lock);
if (pwm->hwpwm >= PCA9685_MAXCHAN) {
unsigned int i;
/*
* Check if any of the GPIOs are requested and in that case
* prevent using the "all LEDs" channel.
*/
for (i = 0; i < pca->gpio.ngpio; i++)
if (gpiochip_is_requested(&pca->gpio, i)) {
is_gpio = true;
break;
}
} else if (pwm_get_chip_data(pwm)) {
is_gpio = true;
}
mutex_unlock(&pca->lock);
return is_gpio;
}
static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
{
struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm = &pca->chip.pwms[offset];
unsigned int value;
regmap_read(pca->regmap, LED_N_ON_H(pwm->hwpwm), &value);
return value & LED_FULL;
}
static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
int value)
{
struct pca9685 *pca = gpiochip_get_data(gpio);
struct pwm_device *pwm = &pca->chip.pwms[offset];
unsigned int on = value ? LED_FULL : 0;
/* Clear both OFF registers */
regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm), 0);
regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm), 0);
/* Set the full ON bit */
regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on);
}
static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
/* Always out */
return 0;
}
static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio,
unsigned int offset)
{
return -EINVAL;
}
static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
unsigned int offset, int value)
{
pca9685_pwm_gpio_set(gpio, offset, value);
return 0;
}
/*
* The PCA9685 has a bit for turning the PWM output full off or on. Some
* boards like Intel Galileo actually uses these as normal GPIOs so we
* expose a GPIO chip here which can exclusively take over the underlying
* PWM channel.
*/
static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
{
struct device *dev = pca->chip.dev;
mutex_init(&pca->lock);
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
pca->gpio.free = pca9685_pwm_gpio_free;
pca->gpio.get_direction = pca9685_pwm_gpio_get_direction;
pca->gpio.direction_input = pca9685_pwm_gpio_direction_input;
pca->gpio.direction_output = pca9685_pwm_gpio_direction_output;
pca->gpio.get = pca9685_pwm_gpio_get;
pca->gpio.set = pca9685_pwm_gpio_set;
pca->gpio.base = -1;
pca->gpio.ngpio = PCA9685_MAXCHAN;
pca->gpio.can_sleep = true;
return devm_gpiochip_add_data(dev, &pca->gpio, pca);
}
#else
static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
struct pwm_device *pwm)
{
return false;
}
static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
{
return 0;
}
#endif
static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) int duty_ns, int period_ns)
{ {
...@@ -117,16 +267,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -117,16 +267,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
udelay(500); udelay(500);
pca->period_ns = period_ns; pca->period_ns = period_ns;
/*
* If the duty cycle did not change, restart PWM with
* the same duty cycle to period ratio and return.
*/
if (duty_ns == pca->duty_ns) {
regmap_update_bits(pca->regmap, PCA9685_MODE1,
MODE1_RESTART, 0x1);
return 0;
}
} else { } else {
dev_err(chip->dev, dev_err(chip->dev,
"prescaler not set: period out of bounds!\n"); "prescaler not set: period out of bounds!\n");
...@@ -264,6 +404,9 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -264,6 +404,9 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{ {
struct pca9685 *pca = to_pca(chip); struct pca9685 *pca = to_pca(chip);
if (pca9685_pwm_is_gpio(pca, pwm))
return -EBUSY;
if (pca->active_cnt++ == 0) if (pca->active_cnt++ == 0)
return regmap_update_bits(pca->regmap, PCA9685_MODE1, return regmap_update_bits(pca->regmap, PCA9685_MODE1,
MODE1_SLEEP, 0x0); MODE1_SLEEP, 0x0);
...@@ -343,9 +486,16 @@ static int pca9685_pwm_probe(struct i2c_client *client, ...@@ -343,9 +486,16 @@ static int pca9685_pwm_probe(struct i2c_client *client,
pca->chip.dev = &client->dev; pca->chip.dev = &client->dev;
pca->chip.base = -1; pca->chip.base = -1;
pca->chip.can_sleep = true;
return pwmchip_add(&pca->chip); ret = pwmchip_add(&pca->chip);
if (ret < 0)
return ret;
ret = pca9685_pwm_gpio_probe(pca);
if (ret < 0)
pwmchip_remove(&pca->chip);
return ret;
} }
static int pca9685_pwm_remove(struct i2c_client *client) static int pca9685_pwm_remove(struct i2c_client *client)
......
...@@ -118,7 +118,7 @@ static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -118,7 +118,7 @@ static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable_unprepare(pc->clk); clk_disable_unprepare(pc->clk);
} }
static struct pwm_ops pxa_pwm_ops = { static const struct pwm_ops pxa_pwm_ops = {
.config = pxa_pwm_config, .config = pxa_pwm_config,
.enable = pxa_pwm_enable, .enable = pxa_pwm_enable,
.disable = pxa_pwm_disable, .disable = pxa_pwm_disable,
......
...@@ -635,7 +635,6 @@ static int sti_pwm_probe(struct platform_device *pdev) ...@@ -635,7 +635,6 @@ static int sti_pwm_probe(struct platform_device *pdev)
pc->chip.ops = &sti_pwm_ops; pc->chip.ops = &sti_pwm_ops;
pc->chip.base = -1; pc->chip.base = -1;
pc->chip.npwm = pc->cdata->pwm_num_devs; pc->chip.npwm = pc->cdata->pwm_num_devs;
pc->chip.can_sleep = true;
ret = pwmchip_add(&pc->chip); ret = pwmchip_add(&pc->chip);
if (ret < 0) { if (ret < 0) {
......
...@@ -340,7 +340,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev) ...@@ -340,7 +340,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
pwm->chip.ops = &sun4i_pwm_ops; pwm->chip.ops = &sun4i_pwm_ops;
pwm->chip.base = -1; pwm->chip.base = -1;
pwm->chip.npwm = pwm->data->npwm; pwm->chip.npwm = pwm->data->npwm;
pwm->chip.can_sleep = true;
pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_xlate = of_pwm_xlate_with_flags;
pwm->chip.of_pwm_n_cells = 3; pwm->chip.of_pwm_n_cells = 3;
......
...@@ -303,7 +303,6 @@ static int twl_pwmled_probe(struct platform_device *pdev) ...@@ -303,7 +303,6 @@ static int twl_pwmled_probe(struct platform_device *pdev)
twl->chip.dev = &pdev->dev; twl->chip.dev = &pdev->dev;
twl->chip.base = -1; twl->chip.base = -1;
twl->chip.can_sleep = true;
mutex_init(&twl->mutex); mutex_init(&twl->mutex);
......
...@@ -323,7 +323,6 @@ static int twl_pwm_probe(struct platform_device *pdev) ...@@ -323,7 +323,6 @@ static int twl_pwm_probe(struct platform_device *pdev)
twl->chip.dev = &pdev->dev; twl->chip.dev = &pdev->dev;
twl->chip.base = -1; twl->chip.base = -1;
twl->chip.npwm = 2; twl->chip.npwm = 2;
twl->chip.can_sleep = true;
mutex_init(&twl->mutex); mutex_init(&twl->mutex);
......
...@@ -184,7 +184,7 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip, ...@@ -184,7 +184,7 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
return 0; return 0;
} }
static struct pwm_ops vt8500_pwm_ops = { static const struct pwm_ops vt8500_pwm_ops = {
.enable = vt8500_pwm_enable, .enable = vt8500_pwm_enable,
.disable = vt8500_pwm_disable, .disable = vt8500_pwm_disable,
.config = vt8500_pwm_config, .config = vt8500_pwm_config,
......
...@@ -284,7 +284,6 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev, ...@@ -284,7 +284,6 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
pwm->ops = &gb_pwm_ops; pwm->ops = &gb_pwm_ops;
pwm->base = -1; /* Allocate base dynamically */ pwm->base = -1; /* Allocate base dynamically */
pwm->npwm = pwmc->pwm_max + 1; pwm->npwm = pwmc->pwm_max + 1;
pwm->can_sleep = true; /* FIXME */
ret = pwmchip_add(pwm); ret = pwmchip_add(pwm);
if (ret) { if (ret) {
......
...@@ -287,8 +287,6 @@ struct pwm_ops { ...@@ -287,8 +287,6 @@ struct pwm_ops {
* @pwms: array of PWM devices allocated by the framework * @pwms: array of PWM devices allocated by the framework
* @of_xlate: request a PWM device given a device tree PWM specifier * @of_xlate: request a PWM device given a device tree PWM specifier
* @of_pwm_n_cells: number of cells expected in the device tree PWM specifier * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
* @can_sleep: must be true if the .config(), .enable() or .disable()
* operations may sleep
*/ */
struct pwm_chip { struct pwm_chip {
struct device *dev; struct device *dev;
...@@ -302,7 +300,6 @@ struct pwm_chip { ...@@ -302,7 +300,6 @@ struct pwm_chip {
struct pwm_device * (*of_xlate)(struct pwm_chip *pc, struct pwm_device * (*of_xlate)(struct pwm_chip *pc,
const struct of_phandle_args *args); const struct of_phandle_args *args);
unsigned int of_pwm_n_cells; unsigned int of_pwm_n_cells;
bool can_sleep;
}; };
/** /**
...@@ -451,8 +448,6 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id); ...@@ -451,8 +448,6 @@ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id);
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
const char *con_id); const char *con_id);
void devm_pwm_put(struct device *dev, struct pwm_device *pwm); void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
bool pwm_can_sleep(struct pwm_device *pwm);
#else #else
static inline struct pwm_device *pwm_request(int pwm_id, const char *label) static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
{ {
...@@ -566,11 +561,6 @@ static inline struct pwm_device *devm_of_pwm_get(struct device *dev, ...@@ -566,11 +561,6 @@ static inline struct pwm_device *devm_of_pwm_get(struct device *dev,
static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm) static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
{ {
} }
static inline bool pwm_can_sleep(struct pwm_device *pwm)
{
return false;
}
#endif #endif
static inline void pwm_apply_args(struct pwm_device *pwm) static inline void pwm_apply_args(struct pwm_device *pwm)
...@@ -613,18 +603,25 @@ struct pwm_lookup { ...@@ -613,18 +603,25 @@ struct pwm_lookup {
const char *con_id; const char *con_id;
unsigned int period; unsigned int period;
enum pwm_polarity polarity; enum pwm_polarity polarity;
const char *module; /* optional, may be NULL */
}; };
#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id, _period, _polarity) \ #define PWM_LOOKUP_WITH_MODULE(_provider, _index, _dev_id, _con_id, \
{ \ _period, _polarity, _module) \
.provider = _provider, \ { \
.index = _index, \ .provider = _provider, \
.dev_id = _dev_id, \ .index = _index, \
.con_id = _con_id, \ .dev_id = _dev_id, \
.period = _period, \ .con_id = _con_id, \
.polarity = _polarity \ .period = _period, \
.polarity = _polarity, \
.module = _module, \
} }
#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id, _period, _polarity) \
PWM_LOOKUP_WITH_MODULE(_provider, _index, _dev_id, _con_id, _period, \
_polarity, NULL)
#if IS_ENABLED(CONFIG_PWM) #if IS_ENABLED(CONFIG_PWM)
void pwm_add_table(struct pwm_lookup *table, size_t num); void pwm_add_table(struct pwm_lookup *table, size_t num);
void pwm_remove_table(struct pwm_lookup *table, size_t num); void pwm_remove_table(struct pwm_lookup *table, size_t num);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册