Commit c70c5fb2 authored by Linus Torvalds's avatar Linus Torvalds

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

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

Pull pwm updates from Thierry Reding:
 "This has a couple of fixes for Atmel, Samsung and Broadcom drivers.

  Some preparatory patches for more upcoming Intel work is included as
  well"

* tag 'pwm/for-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: lpss: pci: Add support for Broxton platform
  pwm: bcm-kona: Don't set polarity in probe
  pwm: Add pwmchip_add_with_polarity() API
  pwm: atmel: Fix incorrect CDTY value after disabling
  pwm: atmel: Fix incorrect CDTY value after enabling
  pwm: samsung: Use MODULE_DEVICE_TABLE() to include OF modalias
  pwm: Add support to remove registered consumer lookup tables
parents 44d21c3f 361c1066
...@@ -223,13 +223,16 @@ void *pwm_get_chip_data(struct pwm_device *pwm) ...@@ -223,13 +223,16 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
EXPORT_SYMBOL_GPL(pwm_get_chip_data); EXPORT_SYMBOL_GPL(pwm_get_chip_data);
/** /**
* pwmchip_add() - register a new PWM chip * pwmchip_add_with_polarity() - register a new PWM chip
* @chip: the PWM chip to add * @chip: the PWM chip to add
* @polarity: initial polarity of PWM channels
* *
* Register a new PWM chip. If chip->base < 0 then a dynamically assigned base * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
* will be used. * will be used. The initial polarity for all channels is specified by the
* @polarity parameter.
*/ */
int pwmchip_add(struct pwm_chip *chip) int pwmchip_add_with_polarity(struct pwm_chip *chip,
enum pwm_polarity polarity)
{ {
struct pwm_device *pwm; struct pwm_device *pwm;
unsigned int i; unsigned int i;
...@@ -259,6 +262,7 @@ int pwmchip_add(struct pwm_chip *chip) ...@@ -259,6 +262,7 @@ int pwmchip_add(struct pwm_chip *chip)
pwm->chip = chip; pwm->chip = chip;
pwm->pwm = chip->base + i; pwm->pwm = chip->base + i;
pwm->hwpwm = i; pwm->hwpwm = i;
pwm->polarity = polarity;
radix_tree_insert(&pwm_tree, pwm->pwm, pwm); radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
} }
...@@ -279,6 +283,19 @@ int pwmchip_add(struct pwm_chip *chip) ...@@ -279,6 +283,19 @@ int pwmchip_add(struct pwm_chip *chip)
mutex_unlock(&pwm_lock); mutex_unlock(&pwm_lock);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity);
/**
* pwmchip_add() - register a new PWM chip
* @chip: the PWM chip to add
*
* Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
* will be used. The initial polarity for all channels is normal.
*/
int pwmchip_add(struct pwm_chip *chip)
{
return pwmchip_add_with_polarity(chip, PWM_POLARITY_NORMAL);
}
EXPORT_SYMBOL_GPL(pwmchip_add); EXPORT_SYMBOL_GPL(pwmchip_add);
/** /**
...@@ -585,6 +602,23 @@ void pwm_add_table(struct pwm_lookup *table, size_t num) ...@@ -585,6 +602,23 @@ void pwm_add_table(struct pwm_lookup *table, size_t num)
mutex_unlock(&pwm_lookup_lock); mutex_unlock(&pwm_lookup_lock);
} }
/**
* pwm_remove_table() - unregister PWM device consumers
* @table: array of consumers to unregister
* @num: number of consumers in table
*/
void pwm_remove_table(struct pwm_lookup *table, size_t num)
{
mutex_lock(&pwm_lookup_lock);
while (num--) {
list_del(&table->list);
table++;
}
mutex_unlock(&pwm_lookup_lock);
}
/** /**
* pwm_get() - look up and request a PWM device * pwm_get() - look up and request a PWM device
* @dev: device for PWM consumer * @dev: device for PWM consumer
......
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -21,6 +23,7 @@ ...@@ -21,6 +23,7 @@
#define PWM_ENA 0x04 #define PWM_ENA 0x04
#define PWM_DIS 0x08 #define PWM_DIS 0x08
#define PWM_SR 0x0C #define PWM_SR 0x0C
#define PWM_ISR 0x1C
/* Bit field in SR */ /* Bit field in SR */
#define PWM_SR_ALL_CH_ON 0x0F #define PWM_SR_ALL_CH_ON 0x0F
...@@ -60,6 +63,9 @@ struct atmel_pwm_chip { ...@@ -60,6 +63,9 @@ struct atmel_pwm_chip {
struct clk *clk; struct clk *clk;
void __iomem *base; void __iomem *base;
unsigned int updated_pwms;
struct mutex isr_lock; /* ISR is cleared when read, ensure only one thread does that */
void (*config)(struct pwm_chip *chip, struct pwm_device *pwm, void (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long dty, unsigned long prd); unsigned long dty, unsigned long prd);
}; };
...@@ -144,6 +150,10 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -144,6 +150,10 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK);
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
atmel_pwm->config(chip, pwm, dty, prd); atmel_pwm->config(chip, pwm, dty, prd);
mutex_lock(&atmel_pwm->isr_lock);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
atmel_pwm->updated_pwms &= ~(1 << pwm->hwpwm);
mutex_unlock(&atmel_pwm->isr_lock);
clk_disable(atmel_pwm->clk); clk_disable(atmel_pwm->clk);
return ret; return ret;
...@@ -155,24 +165,25 @@ static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -155,24 +165,25 @@ static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm,
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
unsigned int val; unsigned int val;
if (test_bit(PWMF_ENABLED, &pwm->flags)) {
/*
* If the PWM channel is enabled, using the update register,
* it needs to set bit 10 of CMR to 0
*/
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty); atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty);
val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR); val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
val &= ~PWM_CMR_UPD_CDTY; val &= ~PWM_CMR_UPD_CDTY;
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val); atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
} else {
/* /*
* If the PWM channel is disabled, write value to duty and * If the PWM channel is enabled, only update CDTY by using the update
* period registers directly. * register, it needs to set bit 10 of CMR to 0
*/
if (test_bit(PWMF_ENABLED, &pwm->flags))
return;
/*
* If the PWM channel is disabled, write value to duty and period
* registers directly.
*/ */
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty); atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty);
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd); atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd);
}
} }
static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm,
...@@ -242,7 +253,22 @@ static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -242,7 +253,22 @@ static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{ {
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
unsigned long timeout = jiffies + 2 * HZ;
/*
* Wait for at least a complete period to have passed before disabling a
* channel to be sure that CDTY has been updated
*/
mutex_lock(&atmel_pwm->isr_lock);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
while (!(atmel_pwm->updated_pwms & (1 << pwm->hwpwm)) &&
time_before(jiffies, timeout)) {
usleep_range(10, 100);
atmel_pwm->updated_pwms |= atmel_pwm_readl(atmel_pwm, PWM_ISR);
}
mutex_unlock(&atmel_pwm->isr_lock);
atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm); atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm);
clk_disable(atmel_pwm->clk); clk_disable(atmel_pwm->clk);
...@@ -357,6 +383,8 @@ static int atmel_pwm_probe(struct platform_device *pdev) ...@@ -357,6 +383,8 @@ static int atmel_pwm_probe(struct platform_device *pdev)
atmel_pwm->chip.npwm = 4; atmel_pwm->chip.npwm = 4;
atmel_pwm->chip.can_sleep = true; atmel_pwm->chip.can_sleep = true;
atmel_pwm->config = data->config; atmel_pwm->config = data->config;
atmel_pwm->updated_pwms = 0;
mutex_init(&atmel_pwm->isr_lock);
ret = pwmchip_add(&atmel_pwm->chip); ret = pwmchip_add(&atmel_pwm->chip);
if (ret < 0) { if (ret < 0) {
...@@ -378,6 +406,7 @@ static int atmel_pwm_remove(struct platform_device *pdev) ...@@ -378,6 +406,7 @@ static int atmel_pwm_remove(struct platform_device *pdev)
struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev); struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
clk_unprepare(atmel_pwm->clk); clk_unprepare(atmel_pwm->clk);
mutex_destroy(&atmel_pwm->isr_lock);
return pwmchip_remove(&atmel_pwm->chip); return pwmchip_remove(&atmel_pwm->chip);
} }
......
...@@ -266,18 +266,15 @@ static int kona_pwmc_probe(struct platform_device *pdev) ...@@ -266,18 +266,15 @@ static int kona_pwmc_probe(struct platform_device *pdev)
return ret; return ret;
} }
/* Set smooth mode, push/pull, and normal polarity for all channels */ /* Set push/pull for all channels */
for (chan = 0; chan < kp->chip.npwm; chan++) { for (chan = 0; chan < kp->chip.npwm; chan++)
value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan)); value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
}
writel(value, kp->base + PWM_CONTROL_OFFSET); writel(value, kp->base + PWM_CONTROL_OFFSET);
clk_disable_unprepare(kp->clk); clk_disable_unprepare(kp->clk);
ret = pwmchip_add(&kp->chip); ret = pwmchip_add_with_polarity(&kp->chip, PWM_POLARITY_INVERSED);
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
......
...@@ -44,8 +44,10 @@ static void pwm_lpss_remove_pci(struct pci_dev *pdev) ...@@ -44,8 +44,10 @@ static void pwm_lpss_remove_pci(struct pci_dev *pdev)
} }
static const struct pci_device_id pwm_lpss_pci_ids[] = { static const struct pci_device_id pwm_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info}, { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
{ PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info}, { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
{ PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bsw_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},
{ }, { },
......
...@@ -456,6 +456,7 @@ static const struct of_device_id samsung_pwm_matches[] = { ...@@ -456,6 +456,7 @@ static const struct of_device_id samsung_pwm_matches[] = {
{ .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant }, { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip) static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
{ {
......
...@@ -182,6 +182,8 @@ struct pwm_chip { ...@@ -182,6 +182,8 @@ struct pwm_chip {
int pwm_set_chip_data(struct pwm_device *pwm, void *data); int pwm_set_chip_data(struct pwm_device *pwm, void *data);
void *pwm_get_chip_data(struct pwm_device *pwm); void *pwm_get_chip_data(struct pwm_device *pwm);
int pwmchip_add_with_polarity(struct pwm_chip *chip,
enum pwm_polarity polarity);
int pwmchip_add(struct pwm_chip *chip); int pwmchip_add(struct pwm_chip *chip);
int pwmchip_remove(struct pwm_chip *chip); int pwmchip_remove(struct pwm_chip *chip);
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
...@@ -217,6 +219,11 @@ static inline int pwmchip_add(struct pwm_chip *chip) ...@@ -217,6 +219,11 @@ static inline int pwmchip_add(struct pwm_chip *chip)
return -EINVAL; return -EINVAL;
} }
static inline int pwmchip_add_inversed(struct pwm_chip *chip)
{
return -EINVAL;
}
static inline int pwmchip_remove(struct pwm_chip *chip) static inline int pwmchip_remove(struct pwm_chip *chip)
{ {
return -EINVAL; return -EINVAL;
...@@ -290,10 +297,15 @@ struct pwm_lookup { ...@@ -290,10 +297,15 @@ struct pwm_lookup {
#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);
#else #else
static inline void pwm_add_table(struct pwm_lookup *table, size_t num) static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
{ {
} }
static inline void pwm_remove_table(struct pwm_lookup *table, size_t num)
{
}
#endif #endif
#ifdef CONFIG_PWM_SYSFS #ifdef CONFIG_PWM_SYSFS
......
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