Commit 7f33e724 authored by Linus Torvalds's avatar Linus Torvalds

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

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
  ...
parents 2dc24b0d 39fd3f99
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);
......
/*
* 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;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
return ERR_PTR(-ENOMEM);
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);
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);
return ERR_CAST(lpwm->regs);
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)
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->period = pwm_get_period(pb->pwm);
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);
......
#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);
......
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