Commit 06b45f2a authored by Linus Torvalds's avatar Linus Torvalds

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

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

Pull pwm changes from Thierry Reding:
 "Not much has been happening in PWM land lately, so this contains
  mostly minor fixes that didn't seem urgent enough for a late
  pull-request last cycle"

* tag 'pwm/for-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: Remove __init initializer for pwm_add_table()
  pwm: samsung: Fix output race on disabling
  pwm: mxs: Fix period divider computation
  pwm: atmel-hlcdc: Add errata handling for sama5d4
  pwm: pca9685: Constify struct regmap_config
  pwm: imx-pwm: add explicit compatible strings and required clock properties
parents b3f4ef0b c264f111
Freescale i.MX PWM controller Freescale i.MX PWM controller
Required properties: Required properties:
- compatible: should be "fsl,<soc>-pwm" - compatible : should be "fsl,<soc>-pwm" and one of the following
compatible strings:
- "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
- 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: should be 2. See pwm.txt in this directory for a description of
the cells format. the cells format.
- clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per"
See the clock consumer binding,
Documentation/devicetree/bindings/clock/clock-bindings.txt
- interrupts: The interrupt for the pwm controller - interrupts: The interrupt for the pwm controller
Example: Example:
...@@ -13,5 +20,8 @@ pwm1: pwm@53fb4000 { ...@@ -13,5 +20,8 @@ pwm1: pwm@53fb4000 {
#pwm-cells = <2>; #pwm-cells = <2>;
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>,
<&clks IMX5_CLK_PWM1_HF_GATE>;
clock-names = "ipg", "per";
interrupts = <61>; interrupts = <61>;
}; };
...@@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(of_pwm_get); ...@@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(of_pwm_get);
* @table: array of consumers to register * @table: array of consumers to register
* @num: number of consumers in table * @num: number of consumers in table
*/ */
void __init pwm_add_table(struct pwm_lookup *table, size_t num) void pwm_add_table(struct pwm_lookup *table, size_t num)
{ {
mutex_lock(&pwm_lookup_lock); mutex_lock(&pwm_lookup_lock);
......
...@@ -225,6 +225,10 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { ...@@ -225,6 +225,10 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
.compatible = "atmel,sama5d3-hlcdc", .compatible = "atmel,sama5d3-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata, .data = &atmel_hlcdc_pwm_sama5d3_errata,
}, },
{
.compatible = "atmel,sama5d4-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata,
},
{ /* sentinel */ }, { /* sentinel */ },
}; };
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
#define PERIOD_CDIV(div) (((div) & 0x7) << 20) #define PERIOD_CDIV(div) (((div) & 0x7) << 20)
#define PERIOD_CDIV_MAX 8 #define PERIOD_CDIV_MAX 8
static const unsigned int cdiv[PERIOD_CDIV_MAX] = {
1, 2, 4, 8, 16, 64, 256, 1024
};
struct mxs_pwm_chip { struct mxs_pwm_chip {
struct pwm_chip chip; struct pwm_chip chip;
struct clk *clk; struct clk *clk;
...@@ -54,13 +58,13 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -54,13 +58,13 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
rate = clk_get_rate(mxs->clk); rate = clk_get_rate(mxs->clk);
while (1) { while (1) {
c = rate / (1 << div); c = rate / cdiv[div];
c = c * period_ns; c = c * period_ns;
do_div(c, 1000000000); do_div(c, 1000000000);
if (c < PERIOD_PERIOD_MAX) if (c < PERIOD_PERIOD_MAX)
break; break;
div++; div++;
if (div > PERIOD_CDIV_MAX) if (div >= PERIOD_CDIV_MAX)
return -EINVAL; return -EINVAL;
} }
......
...@@ -202,7 +202,7 @@ static const struct pwm_ops pca9685_pwm_ops = { ...@@ -202,7 +202,7 @@ static const struct pwm_ops pca9685_pwm_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static struct regmap_config pca9685_regmap_i2c_config = { static const struct regmap_config pca9685_regmap_i2c_config = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.max_register = PCA9685_NUMREGS, .max_register = PCA9685_NUMREGS,
......
...@@ -269,12 +269,31 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -269,12 +269,31 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
spin_unlock_irqrestore(&samsung_pwm_lock, flags); spin_unlock_irqrestore(&samsung_pwm_lock, flags);
} }
static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
struct pwm_device *pwm)
{
unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
u32 tcon;
unsigned long flags;
spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl(chip->base + REG_TCON);
tcon |= TCON_MANUALUPDATE(tcon_chan);
writel(tcon, chip->base + REG_TCON);
tcon &= ~TCON_MANUALUPDATE(tcon_chan);
writel(tcon, chip->base + REG_TCON);
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) int duty_ns, int period_ns)
{ {
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm); struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
u32 tin_ns = chan->tin_ns, tcnt, tcmp; u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp;
/* /*
* We currently avoid using 64bit arithmetic by using the * We currently avoid using 64bit arithmetic by using the
...@@ -288,6 +307,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -288,6 +307,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
return 0; return 0;
tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm)); tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
oldtcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm));
/* We need tick count for calculation, not last tick. */ /* We need tick count for calculation, not last tick. */
++tcnt; ++tcnt;
...@@ -335,6 +355,16 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -335,6 +355,16 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm)); writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm)); writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
/*
* In case the PWM is currently at 100% duty cycle, force a manual
* update to prevent the signal staying high if the PWM is disabled
* shortly afer this update (before it autoreloaded the new values).
*/
if (oldtcmp == (u32) -1) {
dev_dbg(our_chip->chip.dev, "Forcing manual update");
pwm_samsung_manual_update(our_chip, pwm);
}
chan->period_ns = period_ns; chan->period_ns = period_ns;
chan->tin_ns = tin_ns; chan->tin_ns = tin_ns;
chan->duty_ns = duty_ns; chan->duty_ns = duty_ns;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment