Skip to content

Commit

Permalink
Merge tag 'pwm/for-4.11-rc7' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/thierry.reding/linux-pwm

Pull pwm fixes from Thierry Reding:
 "This contain a fix for the atomic update support recently added to
  the Rockchip driver where the clock reference count would become
  unbalanced and result in the clock feeding the PWM to always be
  disabled.

  Another fix to the Intel LPSS driver that adds an update bit quirk
  required for a specific configuration"

* tag 'pwm/for-4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: rockchip: State of PWM clock should synchronize with PWM enabled state
  pwm: lpss: Set enable-bit before waiting for update-bit to go low
  pwm: lpss: Split Tangier configuration
  • Loading branch information
Linus Torvalds committed Apr 13, 2017
2 parents b9b3322 + a900152 commit 827c30a
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 14 deletions.
10 changes: 9 additions & 1 deletion drivers/pwm/pwm-lpss-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
.bypass = true,
};

/* Tangier */
static const struct pwm_lpss_boardinfo pwm_lpss_tng_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
};

static int pwm_lpss_probe_pci(struct pci_dev *pdev,
Expand Down Expand Up @@ -97,7 +105,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
{ PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
{ PCI_VDEVICE(INTEL, 0x11a5), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x11a5), (unsigned long)&pwm_lpss_tng_info},
{ PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
Expand Down
1 change: 1 addition & 0 deletions drivers/pwm/pwm-lpss-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
.clk_rate = 19200000,
.npwm = 4,
.base_unit_bits = 22,
.bypass = true,
};

static int pwm_lpss_probe_platform(struct platform_device *pdev)
Expand Down
19 changes: 13 additions & 6 deletions drivers/pwm/pwm-lpss.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,14 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
}

static int pwm_lpss_update(struct pwm_device *pwm)
static int pwm_lpss_wait_for_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 Configuration register has SW_UPDATE bit that is set when a new
* configuration is written to the register. The bit is automatically
Expand Down Expand Up @@ -122,6 +120,12 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
pwm_lpss_write(pwm, ctrl);
}

static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
{
if (cond)
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
}

static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
Expand All @@ -137,18 +141,21 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
ret = pwm_lpss_update(pwm);
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
pm_runtime_put(chip->dev);
return ret;
}
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true);
} 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);
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
return pwm_lpss_wait_for_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
Expand Down
1 change: 1 addition & 0 deletions drivers/pwm/pwm-lpss.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct pwm_lpss_boardinfo {
unsigned long clk_rate;
unsigned int npwm;
unsigned long base_unit_bits;
bool bypass;
};

struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
Expand Down
40 changes: 33 additions & 7 deletions drivers/pwm/pwm-rockchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,28 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}

static int rockchip_pwm_enable(struct pwm_chip *chip,
struct pwm_device *pwm,
bool enable,
enum pwm_polarity polarity)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
int ret;

if (enable) {
ret = clk_enable(pc->clk);
if (ret)
return ret;
}

pc->data->set_enable(chip, pwm, enable, polarity);

if (!enable)
clk_disable(pc->clk);

return 0;
}

static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
Expand All @@ -207,22 +229,26 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;

if (state->polarity != curstate.polarity && enabled) {
pc->data->set_enable(chip, pwm, false, state->polarity);
ret = rockchip_pwm_enable(chip, pwm, false, state->polarity);
if (ret)
goto out;
enabled = false;
}

ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (ret) {
if (enabled != curstate.enabled)
pc->data->set_enable(chip, pwm, !enabled,
state->polarity);

rockchip_pwm_enable(chip, pwm, !enabled,
state->polarity);
goto out;
}

if (state->enabled != enabled)
pc->data->set_enable(chip, pwm, state->enabled,
state->polarity);
if (state->enabled != enabled) {
ret = rockchip_pwm_enable(chip, pwm, state->enabled,
state->polarity);
if (ret)
goto out;
}

/*
* Update the state with the real hardware, which can differ a bit
Expand Down

0 comments on commit 827c30a

Please sign in to comment.