pwm: Changes for v3.16-rc1
The majority of these changes are cleanups and fixes across all drivers. Redundant error messages are removed and more PWM controllers set the .can_sleep flag to signal that they can't be used in atomic context. Support is added for the Broadcom Kona family of SoCs and the Intel LPSS driver can now probe PCI devices in addition to ACPI devices. Upon shut- down, the pwm-backlight driver will now power off the backlight. It also uses the new descriptor-based GPIO API for more concise GPIO handling. A large chunk of these changes also converts platforms to use the lookup mechanism rather than relying on the global number space to reference PWM devices. This is largely in preparation for more unification and cleanups in future patches. Eventually it will allow the legacy PWM API to be removed. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTl/AqAAoJEN0jrNd/PrOhoZsP/1yLaSK3NuBXWg3VdpH9i8so GXBeh3dbKAmC5MYQlhh5XTvuNBbfOoSp6dGdL3pV9GjcffbqzTynn5YszrbanezX +fqBF1NvW+jb2sUfQmedh9y30O1ADZM0p+FXW/R7e2khiE+8VF2ox35Hc3LLBqk8 SiZoy1UEzIo0BAHgtgCw2VXUYUSYX/KYGoF/t8TCCObKVC3wQ7pW5tN3Ekj14yNL NspM0Q8OsITCQO0PdOfHw1gBmy4iLSuoNpPKP12BQVx5seZ4LBaIz9Wh0jFu89hq zI1gFpGptMsxsaAn/zk6Nr9lHDkqxkhnuYA+dgkA6k0KI9jS1Me20WQEmvM9H9xs BJ8QOfMQP7AHCZeW61J+iPTtCyMwFejRSPMtPjNMfaOQduWJw7+o0GaA30F39dw0 3Cki1C44o9KfwCdC9OcmLignHt5TC1FEJgJL4OY695x0za7XcVgEN6nTg70AQfaz pcm4PeCqtM9jvXdJQdDGDI7gVzT33kpBnGatqQ2bUqMDx8HeHIkdEXehLwsYP46m FX0RJb5ue40esbVWZDGYWJqkdInpHt6deahTW+Jq9Exo4ZMr5/DVkMQCl8oF3/em Y5ED67dnAQ4au1MhElnDTPKk4Uh28aWTYwo8HSO6rt+8jcguH1KvXvLa+z2BcaMv ZVN0ZPy2813ix6Q0yO3D =BDxR -----END PGP SIGNATURE----- Merge tag 'pwm/for-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm Pull pwm changes from Thierry Reding: "The majority of these changes are cleanups and fixes across all drivers. Redundant error messages are removed and more PWM controllers set the .can_sleep flag to signal that they can't be used in atomic context. Support is added for the Broadcom Kona family of SoCs and the Intel LPSS driver can now probe PCI devices in addition to ACPI devices. Upon shutdown, the pwm-backlight driver will now power off the backlight. It also uses the new descriptor-based GPIO API for more concise GPIO handling. A large chunk of these changes also converts platforms to use the lookup mechanism rather than relying on the global number space to reference PWM devices. This is largely in preparation for more unification and cleanups in future patches. Eventually it will allow the legacy PWM API to be removed" * tag 'pwm/for-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (38 commits) pwm: fsl-ftm: set pwm_chip can_sleep flag pwm: ab8500: Fix wrong value shift for disable/enable PWM pwm: samsung: do not set manual update bit in pwm_samsung_config pwm: lp3943: Set pwm_chip can_sleep flag pwm: atmel: set pwm_chip can_sleep flag pwm: mxs: set pwm_chip can_sleep flag pwm: tiehrpwm: inline accessor functions pwm: tiehrpwm: don't build PM related functions when not needed pwm-backlight: retrieve configured PWM period leds: leds-pwm: retrieve configured PWM period ARM: pxa: hx4700: use PWM_LOOKUP to initialize struct pwm_lookup ARM: shmobile: armadillo: use PWM_LOOKUP to initialize struct pwm_lookup ARM: OMAP3: Beagle: use PWM_LOOKUP to initialize struct pwm_lookup pwm: modify PWM_LOOKUP to initialize all struct pwm_lookup members ARM: pxa: hx4700: initialize all the struct pwm_lookup members ARM: OMAP3: Beagle: initialize all the struct pwm_lookup members pwm: renesas-tpu: remove unused struct tpu_pwm_platform_data ARM: shmobile: armadillo: initialize all struct pwm_lookup members pwm: add period and polarity to struct pwm_lookup pwm: twl: Really disable twl6030 PWMs ...
This commit is contained in:
Коммит
7f33e7241d
|
@ -0,0 +1,21 @@
|
|||
Broadcom Kona PWM controller device tree bindings
|
||||
|
||||
This controller has 6 channels.
|
||||
|
||||
Required Properties :
|
||||
- compatible: should contain "brcm,kona-pwm"
|
||||
- reg: physical base address and length of the controller's registers
|
||||
- clocks: phandle + clock specifier pair for the external clock
|
||||
- #pwm-cells: Should be 3. See pwm.txt in this directory for a
|
||||
description of the cells format.
|
||||
|
||||
Refer to clocks/clock-bindings.txt for generic clock consumer properties.
|
||||
|
||||
Example:
|
||||
|
||||
pwm: pwm@3e01a000 {
|
||||
compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm";
|
||||
reg = <0x3e01a000 0xc4>;
|
||||
clocks = <&pwm_clk>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
|
@ -19,7 +19,8 @@ should instead register a static mapping that can be used to match PWM
|
|||
consumers to providers, as given in the following example:
|
||||
|
||||
static struct pwm_lookup board_pwm_lookup[] = {
|
||||
PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL),
|
||||
PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL,
|
||||
50000, PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static void __init board_init(void)
|
||||
|
@ -97,6 +98,13 @@ pwm_chip as argument which provides a description of the PWM chip, the
|
|||
number of PWM devices provided by the chip and the chip-specific
|
||||
implementation of the supported PWM operations to the framework.
|
||||
|
||||
When implementing polarity support in a PWM driver, make sure to respect the
|
||||
signal conventions in the PWM framework. By definition, normal polarity
|
||||
characterizes a signal starts high for the duration of the duty cycle and
|
||||
goes low for the remainder of the period. Conversely, a signal with inversed
|
||||
polarity starts low for the duration of the duty cycle and goes high for the
|
||||
remainder of the period.
|
||||
|
||||
Locking
|
||||
-------
|
||||
|
||||
|
|
|
@ -60,7 +60,8 @@
|
|||
|
||||
static struct pwm_lookup pwm_lookup[] = {
|
||||
/* LEDB -> PMU_STAT */
|
||||
PWM_LOOKUP("twl-pwmled", 1, "leds_pwm", "beagleboard::pmu_stat"),
|
||||
PWM_LOOKUP("twl-pwmled", 1, "leds_pwm", "beagleboard::pmu_stat",
|
||||
7812500, PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
static struct led_pwm pwm_leds[] = {
|
||||
|
|
|
@ -574,7 +574,8 @@ static struct platform_device backlight = {
|
|||
};
|
||||
|
||||
static struct pwm_lookup hx4700_pwm_lookup[] = {
|
||||
PWM_LOOKUP("pxa27x-pwm.1", 0, "pwm-backlight", NULL),
|
||||
PWM_LOOKUP("pxa27x-pwm.1", 0, "pwm-backlight", NULL,
|
||||
30923, PWM_POLARITY_NORMAL),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/gpio_keys.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/platform_data/pwm-renesas-tpu.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/gpio-regulator.h>
|
||||
|
@ -399,24 +399,16 @@ static struct resource pwm_resources[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct tpu_pwm_platform_data pwm_device_data = {
|
||||
.channels[2] = {
|
||||
.polarity = PWM_POLARITY_INVERSED,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device pwm_device = {
|
||||
.name = "renesas-tpu-pwm",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &pwm_device_data,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(pwm_resources),
|
||||
.resource = pwm_resources,
|
||||
};
|
||||
|
||||
static struct pwm_lookup pwm_lookup[] = {
|
||||
PWM_LOOKUP("renesas-tpu-pwm", 2, "pwm-backlight.0", NULL),
|
||||
PWM_LOOKUP("renesas-tpu-pwm", 2, "pwm-backlight.0", NULL,
|
||||
33333, PWM_POLARITY_INVERSED),
|
||||
};
|
||||
|
||||
/* LCDC and backlight */
|
||||
|
|
|
@ -124,8 +124,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
|
|||
samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns;
|
||||
if (bl_data->enable_gpio >= 0)
|
||||
samsung_bl_data->enable_gpio = bl_data->enable_gpio;
|
||||
if (bl_data->enable_gpio_flags)
|
||||
samsung_bl_data->enable_gpio_flags = bl_data->enable_gpio_flags;
|
||||
if (bl_data->init)
|
||||
samsung_bl_data->init = bl_data->init;
|
||||
if (bl_data->notify)
|
||||
|
|
|
@ -181,7 +181,6 @@ static int led_pwm_probe(struct platform_device *pdev)
|
|||
led_dat->cdev.name = cur_led->name;
|
||||
led_dat->cdev.default_trigger = cur_led->default_trigger;
|
||||
led_dat->active_low = cur_led->active_low;
|
||||
led_dat->period = cur_led->pwm_period_ns;
|
||||
led_dat->cdev.brightness_set = led_pwm_set;
|
||||
led_dat->cdev.brightness = LED_OFF;
|
||||
led_dat->cdev.max_brightness = cur_led->max_brightness;
|
||||
|
@ -191,6 +190,10 @@ static int led_pwm_probe(struct platform_device *pdev)
|
|||
if (led_dat->can_sleep)
|
||||
INIT_WORK(&led_dat->work, led_pwm_work);
|
||||
|
||||
led_dat->period = pwm_get_period(led_dat->pwm);
|
||||
if (!led_dat->period && (cur_led->pwm_period_ns > 0))
|
||||
led_dat->period = cur_led->pwm_period_ns;
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
|
|
@ -62,6 +62,15 @@ config PWM_ATMEL_TCB
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-atmel-tcb.
|
||||
|
||||
config PWM_BCM_KONA
|
||||
tristate "Kona PWM support"
|
||||
depends on ARCH_BCM_MOBILE
|
||||
help
|
||||
Generic PWM framework driver for Broadcom Kona PWM block.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-bcm-kona.
|
||||
|
||||
config PWM_BFIN
|
||||
tristate "Blackfin PWM support"
|
||||
depends on BFIN_GPTIMERS
|
||||
|
|
|
@ -3,6 +3,7 @@ obj-$(CONFIG_PWM_SYSFS) += sysfs.o
|
|||
obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
|
||||
obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
|
||||
obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
|
||||
obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o
|
||||
obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
|
||||
obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
|
||||
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
|
||||
|
|
|
@ -661,10 +661,16 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
|||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lookup_lock);
|
||||
|
||||
if (chip)
|
||||
pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm_set_period(pwm, p->period);
|
||||
pwm_set_polarity(pwm, p->polarity);
|
||||
|
||||
mutex_unlock(&pwm_lookup_lock);
|
||||
|
||||
return pwm;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
#define AB8500_PWM_OUT_CTRL2_REG 0x61
|
||||
#define AB8500_PWM_OUT_CTRL7_REG 0x66
|
||||
|
||||
/* backlight driver constants */
|
||||
#define ENABLE_PWM 1
|
||||
#define DISABLE_PWM 0
|
||||
|
||||
struct ab8500_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
@ -64,7 +60,7 @@ static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << (chip->base - 1), ENABLE_PWM);
|
||||
1 << (chip->base - 1), 1 << (chip->base - 1));
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
|
@ -77,11 +73,10 @@ static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << (chip->base - 1), DISABLE_PWM);
|
||||
1 << (chip->base - 1), 0);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct pwm_ops ab8500_pwm_ops = {
|
||||
|
@ -101,10 +96,8 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
|
|||
* device which is required for ab8500 read and write
|
||||
*/
|
||||
ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
|
||||
if (ab8500 == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (ab8500 == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ab8500->chip.dev = &pdev->dev;
|
||||
ab8500->chip.ops = &ab8500_pwm_ops;
|
||||
|
|
|
@ -357,6 +357,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
atmel_pwm->chip.base = -1;
|
||||
atmel_pwm->chip.npwm = 4;
|
||||
atmel_pwm->chip.can_sleep = true;
|
||||
atmel_pwm->config = data->config;
|
||||
|
||||
ret = pwmchip_add(&atmel_pwm->chip);
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* The Kona PWM has some unusual characteristics. Here are the main points.
|
||||
*
|
||||
* 1) There is no disable bit and the hardware docs advise programming a zero
|
||||
* duty to achieve output equivalent to that of a normal disable operation.
|
||||
*
|
||||
* 2) Changes to prescale, duty, period, and polarity do not take effect until
|
||||
* a subsequent rising edge of the trigger bit.
|
||||
*
|
||||
* 3) If the smooth bit and trigger bit are both low, the output is a constant
|
||||
* high signal. Otherwise, the earlier waveform continues to be output.
|
||||
*
|
||||
* 4) If the smooth bit is set on the rising edge of the trigger bit, output
|
||||
* will transition to the new settings on a period boundary (which could be
|
||||
* seconds away). If the smooth bit is clear, new settings will be applied
|
||||
* as soon as possible (the hardware always has a 400ns delay).
|
||||
*
|
||||
* 5) When the external clock that feeds the PWM is disabled, output is pegged
|
||||
* high or low depending on its state at that exact instant.
|
||||
*/
|
||||
|
||||
#define PWM_CONTROL_OFFSET (0x00000000)
|
||||
#define PWM_CONTROL_SMOOTH_SHIFT(chan) (24 + (chan))
|
||||
#define PWM_CONTROL_TYPE_SHIFT(chan) (16 + (chan))
|
||||
#define PWM_CONTROL_POLARITY_SHIFT(chan) (8 + (chan))
|
||||
#define PWM_CONTROL_TRIGGER_SHIFT(chan) (chan)
|
||||
|
||||
#define PRESCALE_OFFSET (0x00000004)
|
||||
#define PRESCALE_SHIFT(chan) ((chan) << 2)
|
||||
#define PRESCALE_MASK(chan) (0x7 << PRESCALE_SHIFT(chan))
|
||||
#define PRESCALE_MIN (0x00000000)
|
||||
#define PRESCALE_MAX (0x00000007)
|
||||
|
||||
#define PERIOD_COUNT_OFFSET(chan) (0x00000008 + ((chan) << 3))
|
||||
#define PERIOD_COUNT_MIN (0x00000002)
|
||||
#define PERIOD_COUNT_MAX (0x00ffffff)
|
||||
|
||||
#define DUTY_CYCLE_HIGH_OFFSET(chan) (0x0000000c + ((chan) << 3))
|
||||
#define DUTY_CYCLE_HIGH_MIN (0x00000000)
|
||||
#define DUTY_CYCLE_HIGH_MAX (0x00ffffff)
|
||||
|
||||
struct kona_pwmc {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
|
||||
{
|
||||
return container_of(_chip, struct kona_pwmc, chip);
|
||||
}
|
||||
|
||||
static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
|
||||
{
|
||||
unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
/* Clear trigger bit but set smooth bit to maintain old output */
|
||||
value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
|
||||
value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
|
||||
writel(value, kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
/* Set trigger bit and clear smooth bit to apply new settings */
|
||||
value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
|
||||
value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
|
||||
writel(value, kp->base + PWM_CONTROL_OFFSET);
|
||||
}
|
||||
|
||||
static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
{
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
u64 val, div, rate;
|
||||
unsigned long prescale = PRESCALE_MIN, pc, dc;
|
||||
unsigned int value, chan = pwm->hwpwm;
|
||||
|
||||
/*
|
||||
* Find period count, duty count and prescale to suit duty_ns and
|
||||
* period_ns. This is done according to formulas described below:
|
||||
*
|
||||
* period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE
|
||||
* duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
|
||||
*
|
||||
* PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
|
||||
* DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
|
||||
*/
|
||||
|
||||
rate = clk_get_rate(kp->clk);
|
||||
|
||||
while (1) {
|
||||
div = 1000000000;
|
||||
div *= 1 + prescale;
|
||||
val = rate * period_ns;
|
||||
pc = div64_u64(val, div);
|
||||
val = rate * duty_ns;
|
||||
dc = div64_u64(val, div);
|
||||
|
||||
/* If duty_ns or period_ns are not achievable then return */
|
||||
if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
|
||||
return -EINVAL;
|
||||
|
||||
/* If pc and dc are in bounds, the calculation is done */
|
||||
if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
|
||||
break;
|
||||
|
||||
/* Otherwise, increase prescale and recalculate pc and dc */
|
||||
if (++prescale > PRESCALE_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the PWM channel is enabled, write the settings to the HW */
|
||||
if (test_bit(PWMF_ENABLED, &pwm->flags)) {
|
||||
value = readl(kp->base + PRESCALE_OFFSET);
|
||||
value &= ~PRESCALE_MASK(chan);
|
||||
value |= prescale << PRESCALE_SHIFT(chan);
|
||||
writel(value, kp->base + PRESCALE_OFFSET);
|
||||
|
||||
writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
|
||||
|
||||
writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
|
||||
|
||||
kona_pwmc_apply_settings(kp, chan);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
enum pwm_polarity polarity)
|
||||
{
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
unsigned int chan = pwm->hwpwm;
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(kp->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
value = readl(kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
if (polarity == PWM_POLARITY_NORMAL)
|
||||
value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
|
||||
else
|
||||
value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan));
|
||||
|
||||
writel(value, kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
kona_pwmc_apply_settings(kp, chan);
|
||||
|
||||
/* Wait for waveform to settle before gating off the clock */
|
||||
ndelay(400);
|
||||
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(kp->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(kp->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
unsigned int chan = pwm->hwpwm;
|
||||
|
||||
/* Simulate a disable by configuring for zero duty */
|
||||
writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
|
||||
kona_pwmc_apply_settings(kp, chan);
|
||||
|
||||
/* Wait for waveform to settle before gating off the clock */
|
||||
ndelay(400);
|
||||
|
||||
clk_disable_unprepare(kp->clk);
|
||||
}
|
||||
|
||||
static const struct pwm_ops kona_pwm_ops = {
|
||||
.config = kona_pwmc_config,
|
||||
.set_polarity = kona_pwmc_set_polarity,
|
||||
.enable = kona_pwmc_enable,
|
||||
.disable = kona_pwmc_disable,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int kona_pwmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct kona_pwmc *kp;
|
||||
struct resource *res;
|
||||
unsigned int chan;
|
||||
unsigned int value = 0;
|
||||
int ret = 0;
|
||||
|
||||
kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
|
||||
if (kp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
|
||||
kp->chip.dev = &pdev->dev;
|
||||
kp->chip.ops = &kona_pwm_ops;
|
||||
kp->chip.base = -1;
|
||||
kp->chip.npwm = 6;
|
||||
kp->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
kp->chip.of_pwm_n_cells = 3;
|
||||
kp->chip.can_sleep = true;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
kp->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(kp->base))
|
||||
return PTR_ERR(kp->base);
|
||||
|
||||
kp->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(kp->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock: %ld\n",
|
||||
PTR_ERR(kp->clk));
|
||||
return PTR_ERR(kp->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(kp->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set smooth mode, push/pull, and normal polarity for all channels */
|
||||
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_POLARITY_SHIFT(chan));
|
||||
}
|
||||
|
||||
writel(value, kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
ret = pwmchip_add(&kp->chip);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kona_pwmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kona_pwmc *kp = platform_get_drvdata(pdev);
|
||||
unsigned int chan;
|
||||
|
||||
for (chan = 0; chan < kp->chip.npwm; chan++)
|
||||
if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags))
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
return pwmchip_remove(&kp->chip);
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_kona_pwmc_dt[] = {
|
||||
{ .compatible = "brcm,kona-pwm" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm_kona_pwmc_dt);
|
||||
|
||||
static struct platform_driver kona_pwmc_driver = {
|
||||
.driver = {
|
||||
.name = "bcm-kona-pwm",
|
||||
.of_match_table = bcm_kona_pwmc_dt,
|
||||
},
|
||||
.probe = kona_pwmc_probe,
|
||||
.remove = kona_pwmc_remove,
|
||||
};
|
||||
module_platform_driver(kona_pwmc_driver);
|
||||
|
||||
MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>");
|
||||
MODULE_AUTHOR("Tim Kryger <tkryger@broadcom.com>");
|
||||
MODULE_DESCRIPTION("Broadcom Kona PWM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -454,6 +454,7 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
|||
fpc->chip.of_pwm_n_cells = 3;
|
||||
fpc->chip.base = -1;
|
||||
fpc->chip.npwm = 8;
|
||||
fpc->chip.can_sleep = true;
|
||||
|
||||
ret = pwmchip_add(&fpc->chip);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -241,10 +241,8 @@ static int imx_pwm_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
|
||||
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
|
||||
if (imx == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (imx == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
imx->clk_per = devm_clk_get(&pdev->dev, "per");
|
||||
if (IS_ERR(imx->clk_per)) {
|
||||
|
|
|
@ -278,6 +278,7 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
|
|||
lp3943_pwm->chip.dev = &pdev->dev;
|
||||
lp3943_pwm->chip.ops = &lp3943_pwm_ops;
|
||||
lp3943_pwm->chip.npwm = LP3943_NUM_PWMS;
|
||||
lp3943_pwm->chip.can_sleep = true;
|
||||
|
||||
platform_set_drvdata(pdev, lp3943_pwm);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Author: Chew Kean Ho <kean.ho.chew@intel.com>
|
||||
* Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com>
|
||||
* Author: Chew Chiau Ee <chiau.ee.chew@intel.com>
|
||||
* Author: Alan Cox <alan@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -19,6 +20,9 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
static int pci_drv, plat_drv; /* So we know which drivers registered */
|
||||
|
||||
#define PWM 0x00000000
|
||||
#define PWM_ENABLE BIT(31)
|
||||
|
@ -34,6 +38,16 @@ struct pwm_lpss_chip {
|
|||
struct pwm_chip chip;
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
unsigned long clk_rate;
|
||||
};
|
||||
|
||||
struct pwm_lpss_boardinfo {
|
||||
unsigned long clk_rate;
|
||||
};
|
||||
|
||||
/* BayTrail */
|
||||
static const struct pwm_lpss_boardinfo byt_info = {
|
||||
25000000
|
||||
};
|
||||
|
||||
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
|
||||
|
@ -55,7 +69,7 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
/* The equation is: base_unit = ((freq / c) * 65536) + correction */
|
||||
base_unit = freq * 65536;
|
||||
|
||||
c = clk_get_rate(lpwm->clk);
|
||||
c = lpwm->clk_rate;
|
||||
if (!c)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -113,52 +127,48 @@ static const struct pwm_ops pwm_lpss_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
|
||||
{ "80860F09", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
|
||||
|
||||
static int pwm_lpss_probe(struct platform_device *pdev)
|
||||
static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev,
|
||||
struct resource *r,
|
||||
const struct pwm_lpss_boardinfo *info)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
lpwm = devm_kzalloc(&pdev->dev, sizeof(*lpwm), GFP_KERNEL);
|
||||
lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
|
||||
if (!lpwm)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
lpwm->regs = devm_ioremap_resource(&pdev->dev, r);
|
||||
lpwm->regs = devm_ioremap_resource(dev, r);
|
||||
if (IS_ERR(lpwm->regs))
|
||||
return PTR_ERR(lpwm->regs);
|
||||
return ERR_CAST(lpwm->regs);
|
||||
|
||||
lpwm->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(lpwm->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get PWM clock\n");
|
||||
return PTR_ERR(lpwm->clk);
|
||||
if (info) {
|
||||
lpwm->clk_rate = info->clk_rate;
|
||||
} else {
|
||||
lpwm->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(lpwm->clk)) {
|
||||
dev_err(dev, "failed to get PWM clock\n");
|
||||
return ERR_CAST(lpwm->clk);
|
||||
}
|
||||
lpwm->clk_rate = clk_get_rate(lpwm->clk);
|
||||
}
|
||||
|
||||
lpwm->chip.dev = &pdev->dev;
|
||||
lpwm->chip.dev = dev;
|
||||
lpwm->chip.ops = &pwm_lpss_ops;
|
||||
lpwm->chip.base = -1;
|
||||
lpwm->chip.npwm = 1;
|
||||
|
||||
ret = pwmchip_add(&lpwm->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
return ret;
|
||||
dev_err(dev, "failed to add PWM chip: %d\n", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, lpwm);
|
||||
return 0;
|
||||
return lpwm;
|
||||
}
|
||||
|
||||
static int pwm_lpss_remove(struct platform_device *pdev)
|
||||
static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = readl(lpwm->regs + PWM);
|
||||
|
@ -167,15 +177,104 @@ static int pwm_lpss_remove(struct platform_device *pdev)
|
|||
return pwmchip_remove(&lpwm->chip);
|
||||
}
|
||||
|
||||
static struct platform_driver pwm_lpss_driver = {
|
||||
static int pwm_lpss_probe_pci(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
const struct pwm_lpss_boardinfo *info;
|
||||
struct pwm_lpss_chip *lpwm;
|
||||
int err;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
info = (struct pwm_lpss_boardinfo *)id->driver_data;
|
||||
lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info);
|
||||
if (IS_ERR(lpwm))
|
||||
return PTR_ERR(lpwm);
|
||||
|
||||
pci_set_drvdata(pdev, lpwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_lpss_remove_pci(struct pci_dev *pdev)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
|
||||
|
||||
pwm_lpss_remove(lpwm);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static struct pci_device_id pwm_lpss_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&byt_info},
|
||||
{ PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&byt_info},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
|
||||
|
||||
static struct pci_driver pwm_lpss_driver_pci = {
|
||||
.name = "pwm-lpss",
|
||||
.id_table = pwm_lpss_pci_ids,
|
||||
.probe = pwm_lpss_probe_pci,
|
||||
.remove = pwm_lpss_remove_pci,
|
||||
};
|
||||
|
||||
static int pwm_lpss_probe_platform(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm;
|
||||
struct resource *r;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
lpwm = pwm_lpss_probe(&pdev->dev, r, NULL);
|
||||
if (IS_ERR(lpwm))
|
||||
return PTR_ERR(lpwm);
|
||||
|
||||
platform_set_drvdata(pdev, lpwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_lpss_remove_platform(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
|
||||
|
||||
return pwm_lpss_remove(lpwm);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
|
||||
{ "80860F09", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
|
||||
|
||||
static struct platform_driver pwm_lpss_driver_platform = {
|
||||
.driver = {
|
||||
.name = "pwm-lpss",
|
||||
.acpi_match_table = pwm_lpss_acpi_match,
|
||||
},
|
||||
.probe = pwm_lpss_probe,
|
||||
.remove = pwm_lpss_remove,
|
||||
.probe = pwm_lpss_probe_platform,
|
||||
.remove = pwm_lpss_remove_platform,
|
||||
};
|
||||
module_platform_driver(pwm_lpss_driver);
|
||||
|
||||
static int __init pwm_init(void)
|
||||
{
|
||||
pci_drv = pci_register_driver(&pwm_lpss_driver_pci);
|
||||
plat_drv = platform_driver_register(&pwm_lpss_driver_platform);
|
||||
if (pci_drv && plat_drv)
|
||||
return pci_drv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(pwm_init);
|
||||
|
||||
static void __exit pwm_exit(void)
|
||||
{
|
||||
if (!pci_drv)
|
||||
pci_unregister_driver(&pwm_lpss_driver_pci);
|
||||
if (!plat_drv)
|
||||
platform_driver_unregister(&pwm_lpss_driver_platform);
|
||||
}
|
||||
module_exit(pwm_exit);
|
||||
|
||||
MODULE_DESCRIPTION("PWM driver for Intel LPSS");
|
||||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||
|
|
|
@ -147,6 +147,7 @@ static int mxs_pwm_probe(struct platform_device *pdev)
|
|||
mxs->chip.dev = &pdev->dev;
|
||||
mxs->chip.ops = &mxs_pwm_ops;
|
||||
mxs->chip.base = -1;
|
||||
mxs->chip.can_sleep = true;
|
||||
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
|
||||
|
|
|
@ -179,10 +179,8 @@ static int pwm_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
|
||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
||||
if (pwm == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (pwm == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pwm->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwm->clk))
|
||||
|
|
|
@ -21,13 +21,14 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/pwm-renesas-tpu.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define TPU_CHANNEL_MAX 4
|
||||
|
||||
#define TPU_TSTR 0x00 /* Timer start register (shared) */
|
||||
|
||||
#define TPU_TCRn 0x00 /* Timer control register */
|
||||
|
@ -87,7 +88,6 @@ struct tpu_pwm_device {
|
|||
|
||||
struct tpu_device {
|
||||
struct platform_device *pdev;
|
||||
enum pwm_polarity polarities[TPU_CHANNEL_MAX];
|
||||
struct pwm_chip chip;
|
||||
spinlock_t lock;
|
||||
|
||||
|
@ -229,7 +229,7 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm)
|
|||
|
||||
pwm->tpu = tpu;
|
||||
pwm->channel = _pwm->hwpwm;
|
||||
pwm->polarity = tpu->polarities[pwm->channel];
|
||||
pwm->polarity = PWM_POLARITY_NORMAL;
|
||||
pwm->prescaler = 0;
|
||||
pwm->period = 0;
|
||||
pwm->duty = 0;
|
||||
|
@ -388,16 +388,6 @@ static const struct pwm_ops tpu_pwm_ops = {
|
|||
* Probe and remove
|
||||
*/
|
||||
|
||||
static void tpu_parse_pdata(struct tpu_device *tpu)
|
||||
{
|
||||
struct tpu_pwm_platform_data *pdata = tpu->pdev->dev.platform_data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tpu->polarities); ++i)
|
||||
tpu->polarities[i] = pdata ? pdata->channels[i].polarity
|
||||
: PWM_POLARITY_NORMAL;
|
||||
}
|
||||
|
||||
static int tpu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tpu_device *tpu;
|
||||
|
@ -405,17 +395,12 @@ static int tpu_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
|
||||
if (tpu == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
if (tpu == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&tpu->lock);
|
||||
tpu->pdev = pdev;
|
||||
|
||||
/* Initialize device configuration from platform data. */
|
||||
tpu_parse_pdata(tpu);
|
||||
|
||||
/* Map memory, get clock and pin control. */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
tpu->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
|
|
@ -335,9 +335,6 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
|
||||
writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
|
||||
|
||||
if (test_bit(PWMF_ENABLED, &pwm->flags))
|
||||
pwm_samsung_enable(chip, pwm);
|
||||
|
||||
chan->period_ns = period_ns;
|
||||
chan->tin_ns = tin_ns;
|
||||
chan->duty_ns = duty_ns;
|
||||
|
|
|
@ -179,10 +179,8 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
|||
u32 val;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
|
||||
|
@ -222,7 +220,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
if (!ret) {
|
||||
if (ret < 0) {
|
||||
clk_unprepare(pc->clk);
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
}
|
||||
|
|
|
@ -173,10 +173,8 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
||||
if (!pwm) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (!pwm)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pwm->dev = &pdev->dev;
|
||||
|
||||
|
|
|
@ -209,10 +209,8 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
|||
u16 status;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
|
|
|
@ -138,12 +138,12 @@ static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
|
|||
return container_of(chip, struct ehrpwm_pwm_chip, chip);
|
||||
}
|
||||
|
||||
static u16 ehrpwm_read(void __iomem *base, int offset)
|
||||
static inline u16 ehrpwm_read(void __iomem *base, int offset)
|
||||
{
|
||||
return readw(base + offset);
|
||||
}
|
||||
|
||||
static void ehrpwm_write(void __iomem *base, int offset, unsigned int val)
|
||||
static inline void ehrpwm_write(void __iomem *base, int offset, unsigned int val)
|
||||
{
|
||||
writew(val & 0xFFFF, base + offset);
|
||||
}
|
||||
|
@ -440,10 +440,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
|||
u16 status;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
|
@ -531,6 +529,7 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
|
|||
return pwmchip_remove(&pc->chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
|
||||
{
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
|
@ -557,7 +556,6 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
|
|||
ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ehrpwm_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
|
|
|
@ -263,14 +263,6 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
|
||||
val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
|
||||
|
|
|
@ -211,10 +211,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip->chip.dev = &pdev->dev;
|
||||
chip->chip.ops = &vt8500_pwm_ops;
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -32,8 +32,7 @@ struct pwm_bl_data {
|
|||
unsigned int *levels;
|
||||
bool enabled;
|
||||
struct regulator *power_supply;
|
||||
int enable_gpio;
|
||||
unsigned long enable_gpio_flags;
|
||||
struct gpio_desc *enable_gpio;
|
||||
unsigned int scale;
|
||||
int (*notify)(struct device *,
|
||||
int brightness);
|
||||
|
@ -54,12 +53,8 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
|
|||
if (err < 0)
|
||||
dev_err(pb->dev, "failed to enable power supply\n");
|
||||
|
||||
if (gpio_is_valid(pb->enable_gpio)) {
|
||||
if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW)
|
||||
gpio_set_value(pb->enable_gpio, 0);
|
||||
else
|
||||
gpio_set_value(pb->enable_gpio, 1);
|
||||
}
|
||||
if (pb->enable_gpio)
|
||||
gpiod_set_value(pb->enable_gpio, 1);
|
||||
|
||||
pwm_enable(pb->pwm);
|
||||
pb->enabled = true;
|
||||
|
@ -73,12 +68,8 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
|
|||
pwm_config(pb->pwm, 0, pb->period);
|
||||
pwm_disable(pb->pwm);
|
||||
|
||||
if (gpio_is_valid(pb->enable_gpio)) {
|
||||
if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW)
|
||||
gpio_set_value(pb->enable_gpio, 1);
|
||||
else
|
||||
gpio_set_value(pb->enable_gpio, 0);
|
||||
}
|
||||
if (pb->enable_gpio)
|
||||
gpiod_set_value(pb->enable_gpio, 0);
|
||||
|
||||
regulator_disable(pb->power_supply);
|
||||
pb->enabled = false;
|
||||
|
@ -148,7 +139,6 @@ static int pwm_backlight_parse_dt(struct device *dev,
|
|||
struct platform_pwm_backlight_data *data)
|
||||
{
|
||||
struct device_node *node = dev->of_node;
|
||||
enum of_gpio_flags flags;
|
||||
struct property *prop;
|
||||
int length;
|
||||
u32 value;
|
||||
|
@ -189,14 +179,6 @@ static int pwm_backlight_parse_dt(struct device *dev,
|
|||
data->max_brightness--;
|
||||
}
|
||||
|
||||
data->enable_gpio = of_get_named_gpio_flags(node, "enable-gpios", 0,
|
||||
&flags);
|
||||
if (data->enable_gpio == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (gpio_is_valid(data->enable_gpio) && (flags & OF_GPIO_ACTIVE_LOW))
|
||||
data->enable_gpio_flags |= PWM_BACKLIGHT_GPIO_ACTIVE_LOW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -256,8 +238,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
} else
|
||||
pb->scale = data->max_brightness;
|
||||
|
||||
pb->enable_gpio = data->enable_gpio;
|
||||
pb->enable_gpio_flags = data->enable_gpio_flags;
|
||||
pb->notify = data->notify;
|
||||
pb->notify_after = data->notify_after;
|
||||
pb->check_fb = data->check_fb;
|
||||
|
@ -265,26 +245,38 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
pb->dev = &pdev->dev;
|
||||
pb->enabled = false;
|
||||
|
||||
if (gpio_is_valid(pb->enable_gpio)) {
|
||||
unsigned long flags;
|
||||
|
||||
if (pb->enable_gpio_flags & PWM_BACKLIGHT_GPIO_ACTIVE_LOW)
|
||||
flags = GPIOF_OUT_INIT_HIGH;
|
||||
pb->enable_gpio = devm_gpiod_get(&pdev->dev, "enable");
|
||||
if (IS_ERR(pb->enable_gpio)) {
|
||||
ret = PTR_ERR(pb->enable_gpio);
|
||||
if (ret == -ENOENT)
|
||||
pb->enable_gpio = NULL;
|
||||
else
|
||||
flags = GPIOF_OUT_INIT_LOW;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
ret = gpio_request_one(pb->enable_gpio, flags, "enable");
|
||||
/*
|
||||
* Compatibility fallback for drivers still using the integer GPIO
|
||||
* platform data. Must go away soon.
|
||||
*/
|
||||
if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) {
|
||||
ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "enable");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n",
|
||||
pb->enable_gpio, ret);
|
||||
data->enable_gpio, ret);
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
pb->enable_gpio = gpio_to_desc(data->enable_gpio);
|
||||
}
|
||||
|
||||
if (pb->enable_gpio)
|
||||
gpiod_direction_output(pb->enable_gpio, 1);
|
||||
|
||||
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
|
||||
if (IS_ERR(pb->power_supply)) {
|
||||
ret = PTR_ERR(pb->power_supply);
|
||||
goto err_gpio;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
|
@ -295,7 +287,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(pb->pwm)) {
|
||||
dev_err(&pdev->dev, "unable to request legacy PWM\n");
|
||||
ret = PTR_ERR(pb->pwm);
|
||||
goto err_gpio;
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,12 +296,15 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
/*
|
||||
* The DT case will set the pwm_period_ns field to 0 and store the
|
||||
* period, parsed from the DT, in the PWM device. For the non-DT case,
|
||||
* set the period from platform data.
|
||||
* set the period from platform data if it has not already been set
|
||||
* via the PWM lookup table.
|
||||
*/
|
||||
if (data->pwm_period_ns > 0)
|
||||
pwm_set_period(pb->pwm, data->pwm_period_ns);
|
||||
|
||||
pb->period = pwm_get_period(pb->pwm);
|
||||
if (!pb->period && (data->pwm_period_ns > 0)) {
|
||||
pb->period = data->pwm_period_ns;
|
||||
pwm_set_period(pb->pwm, data->pwm_period_ns);
|
||||
}
|
||||
|
||||
pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale);
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
|
@ -320,7 +315,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(bl)) {
|
||||
dev_err(&pdev->dev, "failed to register backlight\n");
|
||||
ret = PTR_ERR(bl);
|
||||
goto err_gpio;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
if (data->dft_brightness > data->max_brightness) {
|
||||
|
@ -336,9 +331,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, bl);
|
||||
return 0;
|
||||
|
||||
err_gpio:
|
||||
if (gpio_is_valid(pb->enable_gpio))
|
||||
gpio_free(pb->enable_gpio);
|
||||
err_alloc:
|
||||
if (data->exit)
|
||||
data->exit(&pdev->dev);
|
||||
|
@ -359,6 +351,14 @@ static int pwm_backlight_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_backlight_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct backlight_device *bl = platform_get_drvdata(pdev);
|
||||
struct pwm_bl_data *pb = bl_get_data(bl);
|
||||
|
||||
pwm_backlight_power_off(pb);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pwm_backlight_suspend(struct device *dev)
|
||||
{
|
||||
|
@ -404,6 +404,7 @@ static struct platform_driver pwm_backlight_driver = {
|
|||
},
|
||||
.probe = pwm_backlight_probe,
|
||||
.remove = pwm_backlight_remove,
|
||||
.shutdown = pwm_backlight_shutdown,
|
||||
};
|
||||
|
||||
module_platform_driver(pwm_backlight_driver);
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef __PWM_RENESAS_TPU_H__
|
||||
#define __PWM_RENESAS_TPU_H__
|
||||
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#define TPU_CHANNEL_MAX 4
|
||||
|
||||
struct tpu_pwm_channel_data {
|
||||
enum pwm_polarity polarity;
|
||||
};
|
||||
|
||||
struct tpu_pwm_platform_data {
|
||||
struct tpu_pwm_channel_data channels[TPU_CHANNEL_MAX];
|
||||
};
|
||||
|
||||
#endif /* __PWM_RENESAS_TPU_H__ */
|
|
@ -274,14 +274,18 @@ struct pwm_lookup {
|
|||
unsigned int index;
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
unsigned int period;
|
||||
enum pwm_polarity polarity;
|
||||
};
|
||||
|
||||
#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id) \
|
||||
#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id, _period, _polarity) \
|
||||
{ \
|
||||
.provider = _provider, \
|
||||
.index = _index, \
|
||||
.dev_id = _dev_id, \
|
||||
.con_id = _con_id, \
|
||||
.period = _period, \
|
||||
.polarity = _polarity \
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_PWM)
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
#include <linux/backlight.h>
|
||||
|
||||
/* TODO: convert to gpiod_*() API once it has been merged */
|
||||
#define PWM_BACKLIGHT_GPIO_ACTIVE_LOW (1 << 0)
|
||||
|
||||
struct platform_pwm_backlight_data {
|
||||
int pwm_id;
|
||||
unsigned int max_brightness;
|
||||
|
@ -16,8 +13,8 @@ struct platform_pwm_backlight_data {
|
|||
unsigned int lth_brightness;
|
||||
unsigned int pwm_period_ns;
|
||||
unsigned int *levels;
|
||||
/* TODO remove once all users are switched to gpiod_* API */
|
||||
int enable_gpio;
|
||||
unsigned long enable_gpio_flags;
|
||||
int (*init)(struct device *dev);
|
||||
int (*notify)(struct device *dev, int brightness);
|
||||
void (*notify_after)(struct device *dev, int brightness);
|
||||
|
|
Загрузка…
Ссылка в новой задаче