pwm: Changes for v6.9-rc1
This contains the usual amount of driver and device tree changes. Additionally there is a big rework of how pwm lowlevel drivers are registered to prepare adding character device support. Thanks to Dharma Balasubiramani, Dong Aisheng, Duje Mihanović, Jerome Brunet, Raag Jadav and Rafał Miłecki for their contributions. And sorry for those who still need some patience because I didn't manage to empty my review queue. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEP4GsaTp6HlmJrf7Tj4D7WH0S/k4FAmXuyf4ACgkQj4D7WH0S /k4Yugf+P7gMPuCQJqWLvOyuHjKt4tI3aVsr+jbSiAfbPWaXAQKZunnZ9K17bOI2 JQkDuAi76teNRiVtNEx1ZEdfKe9KgY/Npq8BTmvXxvBktCand8sfhyyRaXYo9FWI B5qKdp1WIg7ZDMoGQtLRayly4FAsbB0L50SjWmkVIXC2xXp6t6KxxgnOgTM58Oo9 0yYYetF3EOmDQ4J234/muaLbM+1rjajKdw+SgS2mry2WV60SOqo+PQfuK42XjWip cLDkEgYogwx1MAbFgobtquA7Hvkdb2WyCirTDNZiGIBtmM89kH4Oa8e4IDR6FRqn w35hJv7sxVjiqBrSMD/lWpJeQ8gPYg== =6Ixv -----END PGP SIGNATURE----- Merge tag 'pwm/for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux Pull pwm updates from Uwe Kleine-König: "This contains the usual amount of driver and device tree changes. Additionally there is a big rework of how pwm lowlevel drivers are registered to prepare adding character device support. Thanks to Dharma Balasubiramani, Dong Aisheng, Duje Mihanović, Jerome Brunet, Raag Jadav and Rafał Miłecki for their contributions. And sorry for those who still need some patience because I didn't manage to empty my review queue" * tag 'pwm/for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux: (185 commits) pwm: imx-tpm: fix probe crash due to access registers without clock pwm: meson: generalize 4 inputs clock on meson8 pwm type dt-bindings: pwm: amlogic: Add a new binding for meson8 pwm types dt-bindings: pwm: amlogic: fix s4 bindings pwm: dwc: simplify error handling pwm: dwc: Add 16 channel support for Intel Elkhart Lake pwm: dwc: drop redundant error check staging: greybus: pwm: Make use of devm_pwmchip_alloc() function staging: greybus: pwm: Rework how the number of PWM lines is determined staging: greybus: pwm: Drop unused gb_connection_set_data() staging: greybus: pwm: Rely on pwm framework to pass a valid hwpwm staging: greybus: pwm: Make use of pwmchip_parent() accessor staging: greybus: pwm: Change prototype of helpers to prepare further changes leds: qcom-lpg: Make use of devm_pwmchip_alloc() function drm/bridge: ti-sn65dsi86: Make use of devm_pwmchip_alloc() function drm/bridge: ti-sn65dsi86: Make use of pwmchip_parent() accessor gpio: mvebu: Make use of devm_pwmchip_alloc() function pwm: xilinx: Make use of devm_pwmchip_alloc() function pwm: xilinx: Prepare removing pwm_chip from driver data pwm: vt8500: Make use of devm_pwmchip_alloc() function ...
This commit is contained in:
commit
aeb152910a
35
Documentation/devicetree/bindings/pwm/atmel,hlcdc-pwm.yaml
Normal file
35
Documentation/devicetree/bindings/pwm/atmel,hlcdc-pwm.yaml
Normal file
@ -0,0 +1,35 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/atmel,hlcdc-pwm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Atmel's HLCDC's PWM controller
|
||||
|
||||
maintainers:
|
||||
- Nicolas Ferre <nicolas.ferre@microchip.com>
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
- Claudiu Beznea <claudiu.beznea@tuxon.dev>
|
||||
|
||||
description:
|
||||
The LCDC integrates a Pulse Width Modulation (PWM) Controller. This block
|
||||
generates the LCD contrast control signal (LCD_PWM) that controls the
|
||||
display's contrast by software. LCDC_PWM is an 8-bit PWM signal that can be
|
||||
converted to an analog voltage with a simple passive filter. LCD display
|
||||
panels have different backlight specifications in terms of minimum/maximum
|
||||
values for PWM frequency. If the LCDC PWM frequency range does not match the
|
||||
LCD display panel, it is possible to use the standalone PWM Controller to
|
||||
drive the backlight.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: atmel,hlcdc-pwm
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#pwm-cells"
|
||||
|
||||
additionalProperties: false
|
@ -1,29 +0,0 @@
|
||||
Device-Tree bindings for Atmel's HLCDC (High-end LCD Controller) PWM driver
|
||||
|
||||
The Atmel HLCDC PWM is subdevice of the HLCDC MFD device.
|
||||
See ../mfd/atmel-hlcdc.txt for more details.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be one of the following:
|
||||
"atmel,hlcdc-pwm"
|
||||
- pinctr-names: the pin control state names. Should contain "default".
|
||||
- pinctrl-0: should contain the pinctrl states described by pinctrl
|
||||
default.
|
||||
- #pwm-cells: should be set to 3. This PWM chip use the default 3 cells
|
||||
bindings defined in pwm.yaml in this directory.
|
||||
|
||||
Example:
|
||||
|
||||
hlcdc: hlcdc@f0030000 {
|
||||
compatible = "atmel,sama5d3-hlcdc";
|
||||
reg = <0xf0030000 0x2000>;
|
||||
clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
|
||||
clock-names = "periph_clk","sys_clk", "slow_clk";
|
||||
|
||||
hlcdc_pwm: hlcdc-pwm {
|
||||
compatible = "atmel,hlcdc-pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lcd_pwm>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
};
|
51
Documentation/devicetree/bindings/pwm/marvell,pxa-pwm.yaml
Normal file
51
Documentation/devicetree/bindings/pwm/marvell,pxa-pwm.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/marvell,pxa-pwm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Marvell PXA PWM
|
||||
|
||||
maintainers:
|
||||
- Duje Mihanović <duje.mihanovic@skole.hr>
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- marvell,pxa250-pwm
|
||||
- marvell,pxa270-pwm
|
||||
- marvell,pxa168-pwm
|
||||
- marvell,pxa910-pwm
|
||||
|
||||
reg:
|
||||
# Length should be 0x10
|
||||
maxItems: 1
|
||||
|
||||
"#pwm-cells":
|
||||
# Used for specifying the period length in nanoseconds
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#pwm-cells"
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/pxa-clock.h>
|
||||
|
||||
pwm0: pwm@40b00000 {
|
||||
compatible = "marvell,pxa250-pwm";
|
||||
reg = <0x40b00000 0x10>;
|
||||
#pwm-cells = <1>;
|
||||
clocks = <&clks CLK_PWM0>;
|
||||
};
|
@ -24,6 +24,7 @@ properties:
|
||||
- mediatek,mt7629-pwm
|
||||
- mediatek,mt7981-pwm
|
||||
- mediatek,mt7986-pwm
|
||||
- mediatek,mt7988-pwm
|
||||
- mediatek,mt8183-pwm
|
||||
- mediatek,mt8365-pwm
|
||||
- mediatek,mt8516-pwm
|
||||
|
@ -9,9 +9,6 @@ title: Amlogic PWM
|
||||
maintainers:
|
||||
- Heiner Kallweit <hkallweit1@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@ -24,31 +21,40 @@ properties:
|
||||
- amlogic,meson-g12a-ee-pwm
|
||||
- amlogic,meson-g12a-ao-pwm-ab
|
||||
- amlogic,meson-g12a-ao-pwm-cd
|
||||
- amlogic,meson-s4-pwm
|
||||
deprecated: true
|
||||
- items:
|
||||
- const: amlogic,meson-gx-pwm
|
||||
- const: amlogic,meson-gxbb-pwm
|
||||
deprecated: true
|
||||
- items:
|
||||
- const: amlogic,meson-gx-ao-pwm
|
||||
- const: amlogic,meson-gxbb-ao-pwm
|
||||
deprecated: true
|
||||
- items:
|
||||
- const: amlogic,meson8-pwm
|
||||
- const: amlogic,meson8b-pwm
|
||||
deprecated: true
|
||||
- enum:
|
||||
- amlogic,meson8-pwm-v2
|
||||
- amlogic,meson-s4-pwm
|
||||
- items:
|
||||
- enum:
|
||||
- amlogic,meson8b-pwm-v2
|
||||
- amlogic,meson-gxbb-pwm-v2
|
||||
- amlogic,meson-axg-pwm-v2
|
||||
- amlogic,meson-g12-pwm-v2
|
||||
- const: amlogic,meson8-pwm-v2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum: [clkin0, clkin1]
|
||||
- items:
|
||||
- const: clkin0
|
||||
- const: clkin1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
@ -57,6 +63,79 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- amlogic,meson8-pwm
|
||||
- amlogic,meson8b-pwm
|
||||
- amlogic,meson-gxbb-pwm
|
||||
- amlogic,meson-gxbb-ao-pwm
|
||||
- amlogic,meson-axg-ee-pwm
|
||||
- amlogic,meson-axg-ao-pwm
|
||||
- amlogic,meson-g12a-ee-pwm
|
||||
- amlogic,meson-g12a-ao-pwm-ab
|
||||
- amlogic,meson-g12a-ao-pwm-cd
|
||||
then:
|
||||
# Obsolete historic bindings tied to the driver implementation
|
||||
# The clocks provided here are meant to be matched with the input
|
||||
# known (hard-coded) in the driver and used to select pwm clock
|
||||
# source. Currently, the linux driver ignores this.
|
||||
# This is kept to maintain ABI backward compatibility.
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum: [clkin0, clkin1]
|
||||
- items:
|
||||
- const: clkin0
|
||||
- const: clkin1
|
||||
|
||||
# Newer binding where clock describe the actual clock inputs of the pwm
|
||||
# block. These are necessary but some inputs may be grounded.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- amlogic,meson8-pwm-v2
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: input clock 0 of the pwm block
|
||||
- description: input clock 1 of the pwm block
|
||||
- description: input clock 2 of the pwm block
|
||||
- description: input clock 3 of the pwm block
|
||||
clock-names: false
|
||||
required:
|
||||
- clocks
|
||||
|
||||
# Newer IP block take a single input per channel, instead of 4 inputs
|
||||
# for both channels
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- amlogic,meson-s4-pwm
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: input clock of PWM channel A
|
||||
- description: input clock of PWM channel B
|
||||
clock-names: false
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -68,3 +147,17 @@ examples:
|
||||
clock-names = "clkin0", "clkin1";
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
- |
|
||||
pwm@2000 {
|
||||
compatible = "amlogic,meson8-pwm-v2";
|
||||
reg = <0x1000 0x10>;
|
||||
clocks = <&xtal>, <0>, <&fdiv4>, <&fdiv5>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
- |
|
||||
pwm@1000 {
|
||||
compatible = "amlogic,meson-s4-pwm";
|
||||
reg = <0x1000 0x10>;
|
||||
clocks = <&pwm_src_a>, <&pwm_src_b>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
|
@ -1,30 +0,0 @@
|
||||
Marvell PWM controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one or more of:
|
||||
- "marvell,pxa250-pwm"
|
||||
- "marvell,pxa270-pwm"
|
||||
- "marvell,pxa168-pwm"
|
||||
- "marvell,pxa910-pwm"
|
||||
- reg: Physical base address and length of the registers used by the PWM channel
|
||||
Note that one device instance must be created for each PWM that is used, so the
|
||||
length covers only the register window for one PWM output, not that of the
|
||||
entire PWM controller. Currently length is 0x10 for all supported devices.
|
||||
- #pwm-cells: Should be 1. This cell is used to specify the period in
|
||||
nanoseconds.
|
||||
|
||||
Example PWM device node:
|
||||
|
||||
pwm0: pwm@40b00000 {
|
||||
compatible = "marvell,pxa250-pwm";
|
||||
reg = <0x40b00000 0x10>;
|
||||
#pwm-cells = <1>;
|
||||
};
|
||||
|
||||
Example PWM client node:
|
||||
|
||||
backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&pwm0 5000000>;
|
||||
...
|
||||
}
|
@ -420,6 +420,7 @@ POWER
|
||||
devm_reboot_mode_unregister()
|
||||
|
||||
PWM
|
||||
devm_pwmchip_alloc()
|
||||
devm_pwmchip_add()
|
||||
devm_pwm_get()
|
||||
devm_fwnode_pwm_get()
|
||||
|
@ -143,11 +143,12 @@ to implement the pwm_*() functions itself. This means that it's impossible
|
||||
to have multiple PWM drivers in the system. For this reason it's mandatory
|
||||
for new drivers to use the generic PWM framework.
|
||||
|
||||
A new PWM controller/chip can be added using pwmchip_add() and removed
|
||||
again with pwmchip_remove(). pwmchip_add() takes a filled in struct
|
||||
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.
|
||||
A new PWM controller/chip can be allocated using pwmchip_alloc(), then
|
||||
registered using pwmchip_add() and removed again with pwmchip_remove(). To undo
|
||||
pwmchip_alloc() use pwmchip_put(). pwmchip_add() takes a filled in struct
|
||||
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
|
||||
|
@ -99,7 +99,6 @@ struct mvebu_pwm {
|
||||
u32 offset;
|
||||
unsigned long clk_rate;
|
||||
struct gpio_desc *gpiod;
|
||||
struct pwm_chip chip;
|
||||
spinlock_t lock;
|
||||
struct mvebu_gpio_chip *mvchip;
|
||||
|
||||
@ -615,7 +614,7 @@ static const struct regmap_config mvebu_gpio_regmap_config = {
|
||||
*/
|
||||
static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct mvebu_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -789,6 +788,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
struct pwm_chip *chip;
|
||||
void __iomem *base;
|
||||
u32 offset;
|
||||
u32 set;
|
||||
@ -813,9 +813,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
|
||||
if (!mvpwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, mvchip->chip.ngpio, sizeof(*mvpwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
mvpwm = to_mvebu_pwm(chip);
|
||||
|
||||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
mvpwm->offset = offset;
|
||||
@ -868,13 +870,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mvpwm->chip.dev = dev;
|
||||
mvpwm->chip.ops = &mvebu_pwm_ops;
|
||||
mvpwm->chip.npwm = mvchip->chip.ngpio;
|
||||
chip->ops = &mvebu_pwm_ops;
|
||||
|
||||
spin_lock_init(&mvpwm->lock);
|
||||
|
||||
return devm_pwmchip_add(dev, &mvpwm->chip);
|
||||
return devm_pwmchip_add(dev, chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -197,7 +197,7 @@ struct ti_sn65dsi86 {
|
||||
DECLARE_BITMAP(gchip_output, SN_NUM_GPIOS);
|
||||
#endif
|
||||
#if defined(CONFIG_PWM)
|
||||
struct pwm_chip pchip;
|
||||
struct pwm_chip *pchip;
|
||||
bool pwm_enabled;
|
||||
atomic_t pwm_pin_busy;
|
||||
#endif
|
||||
@ -1374,7 +1374,7 @@ static void ti_sn_pwm_pin_release(struct ti_sn65dsi86 *pdata)
|
||||
|
||||
static struct ti_sn65dsi86 *pwm_chip_to_ti_sn_bridge(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ti_sn65dsi86, pchip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int ti_sn_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -1415,7 +1415,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int ret;
|
||||
|
||||
if (!pdata->pwm_enabled) {
|
||||
ret = pm_runtime_resume_and_get(chip->dev);
|
||||
ret = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@ -1431,7 +1431,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
SN_GPIO_MUX_MASK << (2 * SN_PWM_GPIO_IDX),
|
||||
SN_GPIO_MUX_SPECIAL << (2 * SN_PWM_GPIO_IDX));
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to mux in PWM function\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to mux in PWM function\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -1507,7 +1507,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = regmap_write(pdata->regmap, SN_PWM_PRE_DIV_REG, pre_div);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to update PWM_PRE_DIV\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to update PWM_PRE_DIV\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1519,7 +1519,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
FIELD_PREP(SN_PWM_INV_MASK, state->polarity == PWM_POLARITY_INVERSED);
|
||||
ret = regmap_write(pdata->regmap, SN_PWM_EN_INV_REG, pwm_en_inv);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to update PWM_EN/PWM_INV\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to update PWM_EN/PWM_INV\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1527,7 +1527,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
out:
|
||||
|
||||
if (!pdata->pwm_enabled)
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1585,24 +1585,28 @@ static const struct pwm_ops ti_sn_pwm_ops = {
|
||||
static int ti_sn_pwm_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
|
||||
|
||||
pdata->pchip.dev = &adev->dev;
|
||||
pdata->pchip.ops = &ti_sn_pwm_ops;
|
||||
pdata->pchip.npwm = 1;
|
||||
pdata->pchip.of_xlate = of_pwm_single_xlate;
|
||||
pdata->pchip.of_pwm_n_cells = 1;
|
||||
pdata->pchip = chip = devm_pwmchip_alloc(&adev->dev, 1, 0);
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
pwmchip_set_drvdata(chip, pdata);
|
||||
|
||||
chip->ops = &ti_sn_pwm_ops;
|
||||
chip->of_xlate = of_pwm_single_xlate;
|
||||
|
||||
devm_pm_runtime_enable(&adev->dev);
|
||||
|
||||
return pwmchip_add(&pdata->pchip);
|
||||
return pwmchip_add(chip);
|
||||
}
|
||||
|
||||
static void ti_sn_pwm_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
|
||||
|
||||
pwmchip_remove(&pdata->pchip);
|
||||
pwmchip_remove(pdata->pchip);
|
||||
|
||||
if (pdata->pwm_enabled)
|
||||
pm_runtime_put_sync(&adev->dev);
|
||||
|
@ -77,7 +77,7 @@ struct lpg {
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
struct pwm_chip pwm;
|
||||
struct pwm_chip *pwm;
|
||||
|
||||
const struct lpg_data *data;
|
||||
|
||||
@ -978,7 +978,7 @@ static int lpg_pattern_mc_clear(struct led_classdev *cdev)
|
||||
|
||||
static inline struct lpg *lpg_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct lpg, pwm);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -1093,13 +1093,17 @@ static const struct pwm_ops lpg_pwm_ops = {
|
||||
|
||||
static int lpg_add_pwm(struct lpg *lpg)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
lpg->pwm.dev = lpg->dev;
|
||||
lpg->pwm.npwm = lpg->num_channels;
|
||||
lpg->pwm.ops = &lpg_pwm_ops;
|
||||
lpg->pwm = chip = devm_pwmchip_alloc(lpg->dev, lpg->num_channels, 0);
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
ret = devm_pwmchip_add(lpg->dev, &lpg->pwm);
|
||||
chip->ops = &lpg_pwm_ops;
|
||||
pwmchip_set_drvdata(chip, lpg);
|
||||
|
||||
ret = devm_pwmchip_add(lpg->dev, chip);
|
||||
if (ret)
|
||||
dev_err_probe(lpg->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -1492,7 +1492,7 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
|
||||
.base_unit_bits = 22,
|
||||
.bypass = true,
|
||||
};
|
||||
struct pwm_lpss_chip *pwm;
|
||||
struct pwm_chip *chip;
|
||||
|
||||
if (!(community->features & PINCTRL_FEATURE_PWM))
|
||||
return 0;
|
||||
@ -1500,8 +1500,8 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
|
||||
if (!IS_REACHABLE(CONFIG_PWM_LPSS))
|
||||
return 0;
|
||||
|
||||
pwm = devm_pwm_lpss_probe(pctrl->dev, community->regs + PWMC, &info);
|
||||
return PTR_ERR_OR_ZERO(pwm);
|
||||
chip = devm_pwm_lpss_probe(pctrl->dev, community->regs + PWMC, &info);
|
||||
return PTR_ERR_OR_ZERO(chip);
|
||||
}
|
||||
|
||||
int intel_pinctrl_probe(struct platform_device *pdev,
|
||||
|
@ -24,310 +24,11 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/pwm.h>
|
||||
|
||||
static DEFINE_MUTEX(pwm_lookup_lock);
|
||||
static LIST_HEAD(pwm_lookup_list);
|
||||
|
||||
/* protects access to pwm_chips */
|
||||
static DEFINE_MUTEX(pwm_lock);
|
||||
|
||||
static DEFINE_IDR(pwm_chips);
|
||||
|
||||
static struct pwm_chip *pwmchip_find_by_name(const char *name)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
unsigned long id, tmp;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
|
||||
const char *chip_name = dev_name(chip->dev);
|
||||
|
||||
if (chip_name && strcmp(chip_name, name) == 0) {
|
||||
mutex_unlock(&pwm_lock);
|
||||
return chip;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int pwm_device_request(struct pwm_device *pwm, const char *label)
|
||||
{
|
||||
int err;
|
||||
struct pwm_chip *chip = pwm->chip;
|
||||
const struct pwm_ops *ops = chip->ops;
|
||||
|
||||
if (test_bit(PWMF_REQUESTED, &pwm->flags))
|
||||
return -EBUSY;
|
||||
|
||||
if (!try_module_get(chip->owner))
|
||||
return -ENODEV;
|
||||
|
||||
if (ops->request) {
|
||||
err = ops->request(chip, pwm);
|
||||
if (err) {
|
||||
module_put(chip->owner);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (ops->get_state) {
|
||||
/*
|
||||
* Zero-initialize state because most drivers are unaware of
|
||||
* .usage_power. The other members of state are supposed to be
|
||||
* set by lowlevel drivers. We still initialize the whole
|
||||
* structure for simplicity even though this might paper over
|
||||
* faulty implementations of .get_state().
|
||||
*/
|
||||
struct pwm_state state = { 0, };
|
||||
|
||||
err = ops->get_state(chip, pwm, &state);
|
||||
trace_pwm_get(pwm, &state, err);
|
||||
|
||||
if (!err)
|
||||
pwm->state = state;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_DEBUG))
|
||||
pwm->last = pwm->state;
|
||||
}
|
||||
|
||||
set_bit(PWMF_REQUESTED, &pwm->flags);
|
||||
pwm->label = label;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pwm_device *
|
||||
of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
|
||||
if (chip->of_pwm_n_cells < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* flags in the third cell are optional */
|
||||
if (args->args_count < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (args->args[0] >= chip->npwm)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pwm = pwm_request_from_chip(chip, args->args[0], NULL);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm->args.period = args->args[1];
|
||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
if (chip->of_pwm_n_cells >= 3) {
|
||||
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
}
|
||||
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
|
||||
|
||||
struct pwm_device *
|
||||
of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
|
||||
if (chip->of_pwm_n_cells < 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* validate that one cell is specified, optionally with flags */
|
||||
if (args->args_count != 1 && args->args_count != 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pwm = pwm_request_from_chip(chip, 0, NULL);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm->args.period = args->args[0];
|
||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
if (args->args_count == 2 && args->args[1] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pwm_single_xlate);
|
||||
|
||||
static void of_pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
if (!chip->dev || !chip->dev->of_node)
|
||||
return;
|
||||
|
||||
if (!chip->of_xlate) {
|
||||
u32 pwm_cells;
|
||||
|
||||
if (of_property_read_u32(chip->dev->of_node, "#pwm-cells",
|
||||
&pwm_cells))
|
||||
pwm_cells = 2;
|
||||
|
||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->of_pwm_n_cells = pwm_cells;
|
||||
}
|
||||
|
||||
of_node_get(chip->dev->of_node);
|
||||
}
|
||||
|
||||
static void of_pwmchip_remove(struct pwm_chip *chip)
|
||||
{
|
||||
if (chip->dev)
|
||||
of_node_put(chip->dev->of_node);
|
||||
}
|
||||
|
||||
static bool pwm_ops_check(const struct pwm_chip *chip)
|
||||
{
|
||||
const struct pwm_ops *ops = chip->ops;
|
||||
|
||||
if (!ops->apply)
|
||||
return false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
|
||||
dev_warn(chip->dev,
|
||||
"Please implement the .get_state() callback\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* __pwmchip_add() - register a new PWM chip
|
||||
* @chip: the PWM chip to add
|
||||
* @owner: reference to the module providing the chip.
|
||||
*
|
||||
* Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the
|
||||
* pwmchip_add wrapper to do this right.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!chip || !chip->dev || !chip->ops || !chip->npwm)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pwm_ops_check(chip))
|
||||
return -EINVAL;
|
||||
|
||||
chip->owner = owner;
|
||||
|
||||
chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL);
|
||||
if (!chip->pwms)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&pwm_lock);
|
||||
kfree(chip->pwms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->id = ret;
|
||||
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
pwm->chip = chip;
|
||||
pwm->hwpwm = i;
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
of_pwmchip_add(chip);
|
||||
|
||||
pwmchip_sysfs_export(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pwmchip_add);
|
||||
|
||||
/**
|
||||
* pwmchip_remove() - remove a PWM chip
|
||||
* @chip: the PWM chip to remove
|
||||
*
|
||||
* Removes a PWM chip.
|
||||
*/
|
||||
void pwmchip_remove(struct pwm_chip *chip)
|
||||
{
|
||||
pwmchip_sysfs_unexport(chip);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
of_pwmchip_remove(chip);
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
idr_remove(&pwm_chips, chip->id);
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
kfree(chip->pwms);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_remove);
|
||||
|
||||
static void devm_pwmchip_remove(void *data)
|
||||
{
|
||||
struct pwm_chip *chip = data;
|
||||
|
||||
pwmchip_remove(chip);
|
||||
}
|
||||
|
||||
int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __pwmchip_add(chip, owner);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_pwmchip_add);
|
||||
|
||||
/**
|
||||
* pwm_request_from_chip() - request a PWM device relative to a PWM chip
|
||||
* @chip: PWM chip
|
||||
* @index: per-chip index of the PWM to request
|
||||
* @label: a literal description string of this PWM
|
||||
*
|
||||
* Returns: A pointer to the PWM device at the given index of the given PWM
|
||||
* chip. A negative error code is returned if the index is not valid for the
|
||||
* specified PWM chip or if the PWM device cannot be requested.
|
||||
*/
|
||||
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
||||
unsigned int index,
|
||||
const char *label)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
int err;
|
||||
|
||||
if (!chip || index >= chip->npwm)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
pwm = &chip->pwms[index];
|
||||
|
||||
err = pwm_device_request(pwm, label);
|
||||
if (err < 0)
|
||||
pwm = ERR_PTR(err);
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_request_from_chip);
|
||||
|
||||
static void pwm_apply_debug(struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
@ -370,18 +71,18 @@ static void pwm_apply_debug(struct pwm_device *pwm,
|
||||
|
||||
if (s2.polarity != state->polarity &&
|
||||
state->duty_cycle < state->period)
|
||||
dev_warn(chip->dev, ".apply ignored .polarity\n");
|
||||
dev_warn(pwmchip_parent(chip), ".apply ignored .polarity\n");
|
||||
|
||||
if (state->enabled &&
|
||||
last->polarity == state->polarity &&
|
||||
last->period > s2.period &&
|
||||
last->period <= state->period)
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
".apply didn't pick the best available period (requested: %llu, applied: %llu, possible: %llu)\n",
|
||||
state->period, s2.period, last->period);
|
||||
|
||||
if (state->enabled && state->period < s2.period)
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
".apply is supposed to round down period (requested: %llu, applied: %llu)\n",
|
||||
state->period, s2.period);
|
||||
|
||||
@ -390,20 +91,20 @@ static void pwm_apply_debug(struct pwm_device *pwm,
|
||||
last->period == s2.period &&
|
||||
last->duty_cycle > s2.duty_cycle &&
|
||||
last->duty_cycle <= state->duty_cycle)
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
".apply didn't pick the best available duty cycle (requested: %llu/%llu, applied: %llu/%llu, possible: %llu/%llu)\n",
|
||||
state->duty_cycle, state->period,
|
||||
s2.duty_cycle, s2.period,
|
||||
last->duty_cycle, last->period);
|
||||
|
||||
if (state->enabled && state->duty_cycle < s2.duty_cycle)
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n",
|
||||
state->duty_cycle, state->period,
|
||||
s2.duty_cycle, s2.period);
|
||||
|
||||
if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
"requested disabled, but yielded enabled with duty > 0\n");
|
||||
|
||||
/* reapply the state that the driver reported being configured. */
|
||||
@ -411,7 +112,7 @@ static void pwm_apply_debug(struct pwm_device *pwm,
|
||||
trace_pwm_apply(pwm, &s1, err);
|
||||
if (err) {
|
||||
*last = s1;
|
||||
dev_err(chip->dev, "failed to reapply current setting\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to reapply current setting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -426,7 +127,7 @@ static void pwm_apply_debug(struct pwm_device *pwm,
|
||||
s1.polarity != last->polarity ||
|
||||
(s1.enabled && s1.period != last->period) ||
|
||||
(s1.enabled && s1.duty_cycle != last->duty_cycle)) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
".apply is not idempotent (ena=%d pol=%d %llu/%llu) -> (ena=%d pol=%d %llu/%llu)\n",
|
||||
s1.enabled, s1.polarity, s1.duty_cycle, s1.period,
|
||||
last->enabled, last->polarity, last->duty_cycle,
|
||||
@ -523,33 +224,6 @@ int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_apply_atomic);
|
||||
|
||||
/**
|
||||
* pwm_capture() - capture and report a PWM signal
|
||||
* @pwm: PWM device
|
||||
* @result: structure to fill with capture result
|
||||
* @timeout: time to wait, in milliseconds, before giving up on capture
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!pwm || !pwm->chip->ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pwm->chip->ops->capture)
|
||||
return -ENOSYS;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_capture);
|
||||
|
||||
/**
|
||||
* pwm_adjust_config() - adjust the current PWM config to the PWM arguments
|
||||
* @pwm: PWM device
|
||||
@ -606,24 +280,367 @@ int pwm_adjust_config(struct pwm_device *pwm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_adjust_config);
|
||||
|
||||
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
|
||||
/**
|
||||
* pwm_capture() - capture and report a PWM signal
|
||||
* @pwm: PWM device
|
||||
* @result: structure to fill with capture result
|
||||
* @timeout: time to wait, in milliseconds, before giving up on capture
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!pwm || !pwm->chip->ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pwm->chip->ops->capture)
|
||||
return -ENOSYS;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_capture);
|
||||
|
||||
static struct pwm_chip *pwmchip_find_by_name(const char *name)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
unsigned long id, tmp;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
|
||||
if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
|
||||
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
|
||||
const char *chip_name = dev_name(pwmchip_parent(chip));
|
||||
|
||||
if (chip_name && strcmp(chip_name, name) == 0) {
|
||||
mutex_unlock(&pwm_lock);
|
||||
return chip;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int pwm_device_request(struct pwm_device *pwm, const char *label)
|
||||
{
|
||||
int err;
|
||||
struct pwm_chip *chip = pwm->chip;
|
||||
const struct pwm_ops *ops = chip->ops;
|
||||
|
||||
if (test_bit(PWMF_REQUESTED, &pwm->flags))
|
||||
return -EBUSY;
|
||||
|
||||
if (!try_module_get(chip->owner))
|
||||
return -ENODEV;
|
||||
|
||||
if (ops->request) {
|
||||
err = ops->request(chip, pwm);
|
||||
if (err) {
|
||||
module_put(chip->owner);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (ops->get_state) {
|
||||
/*
|
||||
* Zero-initialize state because most drivers are unaware of
|
||||
* .usage_power. The other members of state are supposed to be
|
||||
* set by lowlevel drivers. We still initialize the whole
|
||||
* structure for simplicity even though this might paper over
|
||||
* faulty implementations of .get_state().
|
||||
*/
|
||||
struct pwm_state state = { 0, };
|
||||
|
||||
err = ops->get_state(chip, pwm, &state);
|
||||
trace_pwm_get(pwm, &state, err);
|
||||
|
||||
if (!err)
|
||||
pwm->state = state;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_DEBUG))
|
||||
pwm->last = pwm->state;
|
||||
}
|
||||
|
||||
set_bit(PWMF_REQUESTED, &pwm->flags);
|
||||
pwm->label = label;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pwm_request_from_chip() - request a PWM device relative to a PWM chip
|
||||
* @chip: PWM chip
|
||||
* @index: per-chip index of the PWM to request
|
||||
* @label: a literal description string of this PWM
|
||||
*
|
||||
* Returns: A pointer to the PWM device at the given index of the given PWM
|
||||
* chip. A negative error code is returned if the index is not valid for the
|
||||
* specified PWM chip or if the PWM device cannot be requested.
|
||||
*/
|
||||
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
||||
unsigned int index,
|
||||
const char *label)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
int err;
|
||||
|
||||
if (!chip || index >= chip->npwm)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
pwm = &chip->pwms[index];
|
||||
|
||||
err = pwm_device_request(pwm, label);
|
||||
if (err < 0)
|
||||
pwm = ERR_PTR(err);
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_request_from_chip);
|
||||
|
||||
|
||||
struct pwm_device *
|
||||
of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
|
||||
/* period in the second cell and flags in the third cell are optional */
|
||||
if (args->args_count < 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pwm = pwm_request_from_chip(chip, args->args[0], NULL);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
if (args->args_count > 1)
|
||||
pwm->args.period = args->args[1];
|
||||
|
||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
|
||||
|
||||
struct pwm_device *
|
||||
of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
|
||||
pwm = pwm_request_from_chip(chip, 0, NULL);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
if (args->args_count > 1)
|
||||
pwm->args.period = args->args[0];
|
||||
|
||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||
if (args->args_count > 1 && args->args[1] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pwm_single_xlate);
|
||||
|
||||
#define PWMCHIP_ALIGN ARCH_DMA_MINALIGN
|
||||
|
||||
static void *pwmchip_priv(struct pwm_chip *chip)
|
||||
{
|
||||
return (void *)chip + ALIGN(sizeof(*chip), PWMCHIP_ALIGN);
|
||||
}
|
||||
|
||||
/* This is the counterpart to pwmchip_alloc() */
|
||||
void pwmchip_put(struct pwm_chip *chip)
|
||||
{
|
||||
kfree(chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_put);
|
||||
|
||||
struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
size_t alloc_size;
|
||||
|
||||
alloc_size = size_add(ALIGN(sizeof(*chip), PWMCHIP_ALIGN), sizeof_priv);
|
||||
|
||||
chip = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (!chip)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
chip->dev = parent;
|
||||
chip->npwm = npwm;
|
||||
|
||||
pwmchip_set_drvdata(chip, pwmchip_priv(chip));
|
||||
|
||||
return chip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_alloc);
|
||||
|
||||
static void devm_pwmchip_put(void *data)
|
||||
{
|
||||
struct pwm_chip *chip = data;
|
||||
|
||||
pwmchip_put(chip);
|
||||
}
|
||||
|
||||
struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
chip = pwmchip_alloc(parent, npwm, sizeof_priv);
|
||||
if (IS_ERR(chip))
|
||||
return chip;
|
||||
|
||||
ret = devm_add_action_or_reset(parent, devm_pwmchip_put, chip);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return chip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
|
||||
|
||||
static void of_pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node)
|
||||
return;
|
||||
|
||||
if (!chip->of_xlate)
|
||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
||||
|
||||
of_node_get(pwmchip_parent(chip)->of_node);
|
||||
}
|
||||
|
||||
static void of_pwmchip_remove(struct pwm_chip *chip)
|
||||
{
|
||||
if (pwmchip_parent(chip))
|
||||
of_node_put(pwmchip_parent(chip)->of_node);
|
||||
}
|
||||
|
||||
static bool pwm_ops_check(const struct pwm_chip *chip)
|
||||
{
|
||||
const struct pwm_ops *ops = chip->ops;
|
||||
|
||||
if (!ops->apply)
|
||||
return false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
"Please implement the .get_state() callback\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* __pwmchip_add() - register a new PWM chip
|
||||
* @chip: the PWM chip to add
|
||||
* @owner: reference to the module providing the chip.
|
||||
*
|
||||
* Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the
|
||||
* pwmchip_add wrapper to do this right.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!chip || !pwmchip_parent(chip) || !chip->ops || !chip->npwm)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pwm_ops_check(chip))
|
||||
return -EINVAL;
|
||||
|
||||
chip->owner = owner;
|
||||
|
||||
chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL);
|
||||
if (!chip->pwms)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&pwm_lock);
|
||||
kfree(chip->pwms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->id = ret;
|
||||
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
pwm->chip = chip;
|
||||
pwm->hwpwm = i;
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
of_pwmchip_add(chip);
|
||||
|
||||
pwmchip_sysfs_export(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pwmchip_add);
|
||||
|
||||
/**
|
||||
* pwmchip_remove() - remove a PWM chip
|
||||
* @chip: the PWM chip to remove
|
||||
*
|
||||
* Removes a PWM chip.
|
||||
*/
|
||||
void pwmchip_remove(struct pwm_chip *chip)
|
||||
{
|
||||
pwmchip_sysfs_unexport(chip);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
of_pwmchip_remove(chip);
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
idr_remove(&pwm_chips, chip->id);
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
kfree(chip->pwms);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_remove);
|
||||
|
||||
static void devm_pwmchip_remove(void *data)
|
||||
{
|
||||
struct pwm_chip *chip = data;
|
||||
|
||||
pwmchip_remove(chip);
|
||||
}
|
||||
|
||||
int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __pwmchip_add(chip, owner);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_pwmchip_add);
|
||||
|
||||
static struct device_link *pwm_device_link_add(struct device *dev,
|
||||
struct pwm_device *pwm)
|
||||
{
|
||||
@ -635,21 +652,39 @@ static struct device_link *pwm_device_link_add(struct device *dev,
|
||||
* impact the PM sequence ordering: the PWM supplier may get
|
||||
* suspended before the consumer.
|
||||
*/
|
||||
dev_warn(pwm->chip->dev,
|
||||
dev_warn(pwmchip_parent(pwm->chip),
|
||||
"No consumer device specified to create a link to\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dl = device_link_add(dev, pwm->chip->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
|
||||
dl = device_link_add(dev, pwmchip_parent(pwm->chip), DL_FLAG_AUTOREMOVE_CONSUMER);
|
||||
if (!dl) {
|
||||
dev_err(dev, "failed to create device link to %s\n",
|
||||
dev_name(pwm->chip->dev));
|
||||
dev_name(pwmchip_parent(pwm->chip)));
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
unsigned long id, tmp;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
|
||||
if (pwmchip_parent(chip) && device_match_fwnode(pwmchip_parent(chip), fwnode)) {
|
||||
mutex_unlock(&pwm_lock);
|
||||
return chip;
|
||||
}
|
||||
|
||||
mutex_unlock(&pwm_lock);
|
||||
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_pwm_get() - request a PWM via the PWM framework
|
||||
* @dev: device for PWM consumer
|
||||
@ -784,6 +819,9 @@ static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode)
|
||||
return pwm;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(pwm_lookup_lock);
|
||||
static LIST_HEAD(pwm_lookup_list);
|
||||
|
||||
/**
|
||||
* pwm_add_table() - register PWM device consumers
|
||||
* @table: array of consumers to register
|
||||
@ -1105,8 +1143,8 @@ static int pwm_seq_show(struct seq_file *s, void *v)
|
||||
|
||||
seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n",
|
||||
(char *)s->private, chip->id,
|
||||
chip->dev->bus ? chip->dev->bus->name : "no-bus",
|
||||
dev_name(chip->dev), chip->npwm,
|
||||
pwmchip_parent(chip)->bus ? pwmchip_parent(chip)->bus->name : "no-bus",
|
||||
dev_name(pwmchip_parent(chip)), chip->npwm,
|
||||
(chip->npwm != 1) ? "s" : "");
|
||||
|
||||
pwm_dbg_show(chip, s);
|
||||
|
@ -24,13 +24,12 @@
|
||||
#define AB8500_PWM_CLKRATE 9600000
|
||||
|
||||
struct ab8500_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
unsigned int hwid;
|
||||
};
|
||||
|
||||
static struct ab8500_pwm_chip *ab8500_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ab8500_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -92,12 +91,12 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* when disabled.
|
||||
*/
|
||||
if (!state->enabled || duty_steps == 0) {
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
ret = abx500_mask_and_set_register_interruptible(pwmchip_parent(chip),
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << ab8500->hwid, 0);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -115,22 +114,22 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);
|
||||
|
||||
ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
|
||||
ret = abx500_set_register_interruptible(pwmchip_parent(chip), AB8500_MISC,
|
||||
reg, lower_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
|
||||
ret = abx500_set_register_interruptible(pwmchip_parent(chip), AB8500_MISC,
|
||||
(reg + 1), higher_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable */
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
ret = abx500_mask_and_set_register_interruptible(pwmchip_parent(chip),
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << ab8500->hwid, 1 << ab8500->hwid);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
|
||||
return ret;
|
||||
@ -144,7 +143,7 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
|
||||
unsigned int div, duty_steps;
|
||||
|
||||
ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
|
||||
ret = abx500_get_register_interruptible(pwmchip_parent(chip), AB8500_MISC,
|
||||
AB8500_PWM_OUT_CTRL7_REG,
|
||||
&ctrl7);
|
||||
if (ret)
|
||||
@ -157,13 +156,13 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
|
||||
ret = abx500_get_register_interruptible(pwmchip_parent(chip), AB8500_MISC,
|
||||
AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2),
|
||||
&lower_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
|
||||
ret = abx500_get_register_interruptible(pwmchip_parent(chip), AB8500_MISC,
|
||||
AB8500_PWM_OUT_CTRL2_REG + (ab8500->hwid * 2),
|
||||
&higher_val);
|
||||
if (ret)
|
||||
@ -185,6 +184,7 @@ static const struct pwm_ops ab8500_pwm_ops = {
|
||||
|
||||
static int ab8500_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct ab8500_pwm_chip *ab8500;
|
||||
int err;
|
||||
|
||||
@ -195,16 +195,16 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
|
||||
* Nothing to be done in probe, this is required to get the
|
||||
* device which is required for ab8500 read and write
|
||||
*/
|
||||
ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
|
||||
if (ab8500 == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*ab8500));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
ab8500->chip.dev = &pdev->dev;
|
||||
ab8500->chip.ops = &ab8500_pwm_ops;
|
||||
ab8500->chip.npwm = 1;
|
||||
ab8500 = ab8500_pwm_from_chip(chip);
|
||||
|
||||
chip->ops = &ab8500_pwm_ops;
|
||||
ab8500->hwid = pdev->id - 1;
|
||||
|
||||
err = devm_pwmchip_add(&pdev->dev, &ab8500->chip);
|
||||
err = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (err < 0)
|
||||
return dev_err_probe(&pdev->dev, err, "Failed to add pwm chip\n");
|
||||
|
||||
|
@ -32,14 +32,13 @@
|
||||
#define APPLE_PWM_CTRL_OUTPUT_ENABLE BIT(14)
|
||||
|
||||
struct apple_pwm {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
u64 clkrate;
|
||||
};
|
||||
|
||||
static inline struct apple_pwm *to_apple_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct apple_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -103,13 +102,16 @@ static const struct pwm_ops apple_pwm_ops = {
|
||||
|
||||
static int apple_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct apple_pwm *fpwm;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
fpwm = devm_kzalloc(&pdev->dev, sizeof(*fpwm), GFP_KERNEL);
|
||||
if (!fpwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*fpwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
fpwm = to_apple_pwm(chip);
|
||||
|
||||
fpwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(fpwm->base))
|
||||
@ -129,11 +131,9 @@ static int apple_pwm_probe(struct platform_device *pdev)
|
||||
if (fpwm->clkrate > NSEC_PER_SEC)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock out of range");
|
||||
|
||||
fpwm->chip.dev = &pdev->dev;
|
||||
fpwm->chip.npwm = 1;
|
||||
fpwm->chip.ops = &apple_pwm_ops;
|
||||
chip->ops = &apple_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &fpwm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "unable to add pwm chip");
|
||||
|
||||
|
@ -28,7 +28,6 @@ struct atmel_hlcdc_pwm_errata {
|
||||
};
|
||||
|
||||
struct atmel_hlcdc_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct atmel_hlcdc *hlcdc;
|
||||
struct clk *cur_clk;
|
||||
const struct atmel_hlcdc_pwm_errata *errata;
|
||||
@ -36,7 +35,7 @@ struct atmel_hlcdc_pwm {
|
||||
|
||||
static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct atmel_hlcdc_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -182,10 +181,12 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
|
||||
|
||||
static int atmel_hlcdc_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
|
||||
struct pwm_device *pwm = &chip->pwms[0];
|
||||
|
||||
/* Keep the periph clock enabled if the PWM is still running. */
|
||||
if (pwm_is_enabled(&atmel->chip.pwms[0]))
|
||||
if (!pwm->state.enabled)
|
||||
clk_disable_unprepare(atmel->hlcdc->periph_clk);
|
||||
|
||||
return 0;
|
||||
@ -193,21 +194,19 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev)
|
||||
|
||||
static int atmel_hlcdc_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
|
||||
struct pwm_state state;
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
|
||||
struct pwm_device *pwm = &chip->pwms[0];
|
||||
int ret;
|
||||
|
||||
pwm_get_state(&atmel->chip.pwms[0], &state);
|
||||
|
||||
/* Re-enable the periph clock it was stopped during suspend. */
|
||||
if (!state.enabled) {
|
||||
if (!pwm->state.enabled) {
|
||||
ret = clk_prepare_enable(atmel->hlcdc->periph_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0],
|
||||
&state);
|
||||
return atmel_hlcdc_pwm_apply(chip, pwm, &pwm->state);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops,
|
||||
@ -243,15 +242,17 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_chip *chip;
|
||||
struct atmel_hlcdc_pwm *atmel;
|
||||
struct atmel_hlcdc *hlcdc;
|
||||
int ret;
|
||||
|
||||
hlcdc = dev_get_drvdata(dev->parent);
|
||||
|
||||
atmel = devm_kzalloc(dev, sizeof(*atmel), GFP_KERNEL);
|
||||
if (!atmel)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, 1, sizeof(*atmel));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
atmel = to_atmel_hlcdc_pwm(chip);
|
||||
|
||||
ret = clk_prepare_enable(hlcdc->periph_clk);
|
||||
if (ret)
|
||||
@ -262,26 +263,25 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
|
||||
atmel->errata = match->data;
|
||||
|
||||
atmel->hlcdc = hlcdc;
|
||||
atmel->chip.ops = &atmel_hlcdc_pwm_ops;
|
||||
atmel->chip.dev = dev;
|
||||
atmel->chip.npwm = 1;
|
||||
chip->ops = &atmel_hlcdc_pwm_ops;
|
||||
|
||||
ret = pwmchip_add(&atmel->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(hlcdc->periph_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, atmel);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_hlcdc_pwm *atmel = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
|
||||
|
||||
pwmchip_remove(&atmel->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_disable_unprepare(atmel->hlcdc->periph_clk);
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ struct atmel_tcb_channel {
|
||||
};
|
||||
|
||||
struct atmel_tcb_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
spinlock_t lock;
|
||||
u8 channel;
|
||||
u8 width;
|
||||
@ -63,7 +62,7 @@ static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128, 0, };
|
||||
|
||||
static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct atmel_tcb_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int atmel_tcb_pwm_request(struct pwm_chip *chip,
|
||||
@ -327,7 +326,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if ((atcbpwm && atcbpwm->duty > 0 &&
|
||||
atcbpwm->duty != atcbpwm->period) &&
|
||||
(atcbpwm->div != i || atcbpwm->period != period)) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"failed to configure period_ns: PWM group already configured with a different value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -388,6 +387,7 @@ static const struct of_device_id atmel_tcb_of_match[] = {
|
||||
|
||||
static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
const struct of_device_id *match;
|
||||
struct atmel_tcb_pwm_chip *tcbpwm;
|
||||
const struct atmel_tcb_config *config;
|
||||
@ -396,9 +396,10 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
int channel;
|
||||
|
||||
tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
|
||||
if (tcbpwm == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, NPWM, sizeof(*tcbpwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
tcbpwm = to_tcb_chip(chip);
|
||||
|
||||
err = of_property_read_u32(np, "reg", &channel);
|
||||
if (err < 0) {
|
||||
@ -436,9 +437,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
tcbpwm->chip.dev = &pdev->dev;
|
||||
tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
|
||||
tcbpwm->chip.npwm = NPWM;
|
||||
chip->ops = &atmel_tcb_pwm_ops;
|
||||
tcbpwm->channel = channel;
|
||||
tcbpwm->width = config->counter_width;
|
||||
|
||||
@ -448,11 +447,11 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&tcbpwm->lock);
|
||||
|
||||
err = pwmchip_add(&tcbpwm->chip);
|
||||
err = pwmchip_add(chip);
|
||||
if (err < 0)
|
||||
goto err_disable_clk;
|
||||
|
||||
platform_set_drvdata(pdev, tcbpwm);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -473,9 +472,10 @@ err_slow_clk:
|
||||
|
||||
static void atmel_tcb_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = to_tcb_chip(chip);
|
||||
|
||||
pwmchip_remove(&tcbpwm->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_disable_unprepare(tcbpwm->slow_clk);
|
||||
clk_put(tcbpwm->gclk);
|
||||
@ -491,7 +491,8 @@ MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);
|
||||
|
||||
static int atmel_tcb_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = to_tcb_chip(chip);
|
||||
struct atmel_tcb_channel *chan = &tcbpwm->bkup;
|
||||
unsigned int channel = tcbpwm->channel;
|
||||
|
||||
@ -505,7 +506,8 @@ static int atmel_tcb_pwm_suspend(struct device *dev)
|
||||
|
||||
static int atmel_tcb_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct atmel_tcb_pwm_chip *tcbpwm = to_tcb_chip(chip);
|
||||
struct atmel_tcb_channel *chan = &tcbpwm->bkup;
|
||||
unsigned int channel = tcbpwm->channel;
|
||||
|
||||
|
@ -77,7 +77,6 @@ struct atmel_pwm_data {
|
||||
};
|
||||
|
||||
struct atmel_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
const struct atmel_pwm_data *data;
|
||||
@ -99,7 +98,7 @@ struct atmel_pwm_chip {
|
||||
|
||||
static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct atmel_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip,
|
||||
@ -210,7 +209,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
|
||||
shift = fls(cycles) - atmel_pwm->data->cfg.period_bits;
|
||||
|
||||
if (shift > PWM_MAX_PRES) {
|
||||
dev_err(chip->dev, "pres exceeds the maximum value\n");
|
||||
dev_err(pwmchip_parent(chip), "pres exceeds the maximum value\n");
|
||||
return -EINVAL;
|
||||
} else if (shift > 0) {
|
||||
*pres = shift;
|
||||
@ -294,19 +293,16 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
|
||||
struct pwm_state cstate;
|
||||
unsigned long cprd, cdty;
|
||||
u32 pres, val;
|
||||
int ret;
|
||||
|
||||
pwm_get_state(pwm, &cstate);
|
||||
|
||||
if (state->enabled) {
|
||||
unsigned long clkrate = clk_get_rate(atmel_pwm->clk);
|
||||
|
||||
if (cstate.enabled &&
|
||||
cstate.polarity == state->polarity &&
|
||||
cstate.period == state->period) {
|
||||
if (pwm->state.enabled &&
|
||||
pwm->state.polarity == state->polarity &&
|
||||
pwm->state.period == state->period) {
|
||||
u32 cmr = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
|
||||
|
||||
cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
|
||||
@ -321,19 +317,19 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd,
|
||||
&pres);
|
||||
if (ret) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"failed to calculate cprd and prescaler\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
|
||||
|
||||
if (cstate.enabled) {
|
||||
if (pwm->state.enabled) {
|
||||
atmel_pwm_disable(chip, pwm, false);
|
||||
} else {
|
||||
ret = clk_enable(atmel_pwm->clk);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to enable clock\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -348,7 +344,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
|
||||
atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty);
|
||||
atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm);
|
||||
} else if (cstate.enabled) {
|
||||
} else if (pwm->state.enabled) {
|
||||
atmel_pwm_disable(chip, pwm, true);
|
||||
}
|
||||
|
||||
@ -462,8 +458,9 @@ static const struct of_device_id atmel_pwm_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
|
||||
|
||||
static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
|
||||
static int atmel_pwm_enable_clk_if_on(struct pwm_chip *chip, bool on)
|
||||
{
|
||||
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
|
||||
unsigned int i, cnt = 0;
|
||||
unsigned long sr;
|
||||
int ret = 0;
|
||||
@ -472,7 +469,7 @@ static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
|
||||
if (!sr)
|
||||
return 0;
|
||||
|
||||
cnt = bitmap_weight(&sr, atmel_pwm->chip.npwm);
|
||||
cnt = bitmap_weight(&sr, chip->npwm);
|
||||
|
||||
if (!on)
|
||||
goto disable_clk;
|
||||
@ -480,7 +477,7 @@ static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
|
||||
for (i = 0; i < cnt; i++) {
|
||||
ret = clk_enable(atmel_pwm->clk);
|
||||
if (ret) {
|
||||
dev_err(atmel_pwm->chip.dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"failed to enable clock for pwm %pe\n",
|
||||
ERR_PTR(ret));
|
||||
|
||||
@ -501,12 +498,14 @@ disable_clk:
|
||||
static int atmel_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_pwm_chip *atmel_pwm;
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL);
|
||||
if (!atmel_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 4, sizeof(*atmel_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
atmel_pwm = to_atmel_pwm_chip(chip);
|
||||
atmel_pwm->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
atmel_pwm->update_pending = 0;
|
||||
@ -521,15 +520,13 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(atmel_pwm->clk),
|
||||
"failed to get prepared PWM clock\n");
|
||||
|
||||
atmel_pwm->chip.dev = &pdev->dev;
|
||||
atmel_pwm->chip.ops = &atmel_pwm_ops;
|
||||
atmel_pwm->chip.npwm = 4;
|
||||
chip->ops = &atmel_pwm_ops;
|
||||
|
||||
ret = atmel_pwm_enable_clk_if_on(atmel_pwm, true);
|
||||
ret = atmel_pwm_enable_clk_if_on(chip, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &atmel_pwm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
goto disable_clk;
|
||||
@ -538,7 +535,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
disable_clk:
|
||||
atmel_pwm_enable_clk_if_on(atmel_pwm, false);
|
||||
atmel_pwm_enable_clk_if_on(chip, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -34,14 +34,13 @@
|
||||
#define IPROC_PWM_PRESCALE_MAX 0x3f
|
||||
|
||||
struct iproc_pwmc {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline struct iproc_pwmc *to_iproc_pwmc(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct iproc_pwmc, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void iproc_pwmc_enable(struct iproc_pwmc *ip, unsigned int channel)
|
||||
@ -187,20 +186,20 @@ static const struct pwm_ops iproc_pwm_ops = {
|
||||
|
||||
static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct iproc_pwmc *ip;
|
||||
unsigned int i;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
ip = devm_kzalloc(&pdev->dev, sizeof(*ip), GFP_KERNEL);
|
||||
if (!ip)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 4, sizeof(*ip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
ip = to_iproc_pwmc(chip);
|
||||
|
||||
platform_set_drvdata(pdev, ip);
|
||||
|
||||
ip->chip.dev = &pdev->dev;
|
||||
ip->chip.ops = &iproc_pwm_ops;
|
||||
ip->chip.npwm = 4;
|
||||
chip->ops = &iproc_pwm_ops;
|
||||
|
||||
ip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ip->base))
|
||||
@ -214,14 +213,14 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||
/* Set full drive and normal polarity for all channels */
|
||||
value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
|
||||
|
||||
for (i = 0; i < ip->chip.npwm; i++) {
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
value &= ~(1 << IPROC_PWM_CTRL_TYPE_SHIFT(i));
|
||||
value |= 1 << IPROC_PWM_CTRL_POLARITY_SHIFT(i);
|
||||
}
|
||||
|
||||
writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &ip->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to add PWM chip\n");
|
||||
|
@ -56,14 +56,13 @@
|
||||
#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);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -164,7 +163,7 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = clk_prepare_enable(kp->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock: %d\n", ret);
|
||||
dev_err(pwmchip_parent(chip), "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -193,7 +192,7 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = clk_prepare_enable(kp->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock: %d\n", ret);
|
||||
dev_err(pwmchip_parent(chip), "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -273,18 +272,18 @@ static const struct pwm_ops kona_pwm_ops = {
|
||||
|
||||
static int kona_pwmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct kona_pwmc *kp;
|
||||
unsigned int chan;
|
||||
unsigned int value = 0;
|
||||
int ret = 0;
|
||||
|
||||
kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
|
||||
if (kp == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 6, sizeof(*kp));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
kp = to_kona_pwmc(chip);
|
||||
|
||||
kp->chip.dev = &pdev->dev;
|
||||
kp->chip.ops = &kona_pwm_ops;
|
||||
kp->chip.npwm = 6;
|
||||
chip->ops = &kona_pwm_ops;
|
||||
|
||||
kp->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(kp->base))
|
||||
@ -304,14 +303,14 @@ static int kona_pwmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Set push/pull for all channels */
|
||||
for (chan = 0; chan < kp->chip.npwm; chan++)
|
||||
for (chan = 0; chan < chip->npwm; chan++)
|
||||
value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
|
||||
|
||||
writel(value, kp->base + PWM_CONTROL_OFFSET);
|
||||
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &kp->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
|
||||
|
@ -24,8 +24,6 @@
|
||||
#define PERIOD_MIN 0x2
|
||||
|
||||
struct bcm2835_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned long rate;
|
||||
@ -33,7 +31,7 @@ struct bcm2835_pwm {
|
||||
|
||||
static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct bcm2835_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -135,14 +133,14 @@ static void devm_clk_rate_exclusive_put(void *data)
|
||||
|
||||
static int bcm2835_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct bcm2835_pwm *pc;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
|
||||
pc->dev = &pdev->dev;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_bcm2835_pwm(chip);
|
||||
|
||||
pc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->base))
|
||||
@ -168,14 +166,12 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"failed to get clock rate\n");
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &bcm2835_pwm_ops;
|
||||
pc->chip.atomic = true;
|
||||
pc->chip.npwm = 2;
|
||||
chip->ops = &bcm2835_pwm_ops;
|
||||
chip->atomic = true;
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to add pwmchip\n");
|
||||
|
@ -49,7 +49,6 @@ struct berlin_pwm_channel {
|
||||
};
|
||||
|
||||
struct berlin_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct berlin_pwm_channel channel[BERLIN_PWM_NUMPWMS];
|
||||
@ -57,7 +56,7 @@ struct berlin_pwm_chip {
|
||||
|
||||
static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct berlin_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *bpc,
|
||||
@ -198,12 +197,14 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match);
|
||||
|
||||
static int berlin_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct berlin_pwm_chip *bpc;
|
||||
int ret;
|
||||
|
||||
bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL);
|
||||
if (!bpc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, BERLIN_PWM_NUMPWMS, sizeof(*bpc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
bpc = to_berlin_pwm_chip(chip);
|
||||
|
||||
bpc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(bpc->base))
|
||||
@ -213,25 +214,24 @@ static int berlin_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(bpc->clk))
|
||||
return PTR_ERR(bpc->clk);
|
||||
|
||||
bpc->chip.dev = &pdev->dev;
|
||||
bpc->chip.ops = &berlin_pwm_ops;
|
||||
bpc->chip.npwm = BERLIN_PWM_NUMPWMS;
|
||||
chip->ops = &berlin_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &bpc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
platform_set_drvdata(pdev, bpc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int berlin_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct berlin_pwm_channel *channel = &bpc->channel[i];
|
||||
|
||||
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
|
||||
@ -247,7 +247,8 @@ static int berlin_pwm_suspend(struct device *dev)
|
||||
|
||||
static int berlin_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
@ -255,7 +256,7 @@ static int berlin_pwm_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct berlin_pwm_channel *channel = &bpc->channel[i];
|
||||
|
||||
berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
||||
|
@ -54,7 +54,6 @@
|
||||
struct brcmstb_pwm {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
|
||||
@ -77,7 +76,7 @@ static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
|
||||
|
||||
static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct brcmstb_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -230,12 +229,14 @@ MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
|
||||
|
||||
static int brcmstb_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct brcmstb_pwm *p;
|
||||
int ret;
|
||||
|
||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*p));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
p = to_brcmstb_pwm(chip);
|
||||
|
||||
p->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(p->clk))
|
||||
@ -244,15 +245,13 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, p);
|
||||
|
||||
p->chip.dev = &pdev->dev;
|
||||
p->chip.ops = &brcmstb_pwm_ops;
|
||||
p->chip.npwm = 2;
|
||||
chip->ops = &brcmstb_pwm_ops;
|
||||
|
||||
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p->base))
|
||||
return PTR_ERR(p->base);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &p->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -28,12 +28,14 @@
|
||||
#include <linux/pwm.h>
|
||||
|
||||
struct pwm_clk_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
bool clk_enabled;
|
||||
};
|
||||
|
||||
#define to_pwm_clk_chip(_chip) container_of(_chip, struct pwm_clk_chip, chip)
|
||||
static inline struct pwm_clk_chip *to_pwm_clk_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
@ -81,35 +83,36 @@ static const struct pwm_ops pwm_clk_ops = {
|
||||
|
||||
static int pwm_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct pwm_clk_chip *pcchip;
|
||||
int ret;
|
||||
|
||||
pcchip = devm_kzalloc(&pdev->dev, sizeof(*pcchip), GFP_KERNEL);
|
||||
if (!pcchip)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pcchip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pcchip = to_pwm_clk_chip(chip);
|
||||
|
||||
pcchip->clk = devm_clk_get_prepared(&pdev->dev, NULL);
|
||||
if (IS_ERR(pcchip->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcchip->clk),
|
||||
"Failed to get clock\n");
|
||||
|
||||
pcchip->chip.dev = &pdev->dev;
|
||||
pcchip->chip.ops = &pwm_clk_ops;
|
||||
pcchip->chip.npwm = 1;
|
||||
chip->ops = &pwm_clk_ops;
|
||||
|
||||
ret = pwmchip_add(&pcchip->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to add pwm chip\n");
|
||||
|
||||
platform_set_drvdata(pdev, pcchip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_clk_chip *pcchip = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct pwm_clk_chip *pcchip = to_pwm_clk_chip(chip);
|
||||
|
||||
pwmchip_remove(&pcchip->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
if (pcchip->clk_enabled)
|
||||
clk_disable(pcchip->clk);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <linux/pwm.h>
|
||||
|
||||
struct clps711x_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *pmpcon;
|
||||
struct clk *clk;
|
||||
spinlock_t lock;
|
||||
@ -20,7 +19,7 @@ struct clps711x_chip {
|
||||
|
||||
static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct clps711x_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -74,22 +73,15 @@ static const struct pwm_ops clps711x_pwm_ops = {
|
||||
.apply = clps711x_pwm_apply,
|
||||
};
|
||||
|
||||
static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
if (args->args[0] >= chip->npwm)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return pwm_request_from_chip(chip, args->args[0], NULL);
|
||||
}
|
||||
|
||||
static int clps711x_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct clps711x_chip *priv;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = to_clps711x_chip(chip);
|
||||
|
||||
priv->pmpcon = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->pmpcon))
|
||||
@ -99,15 +91,11 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(priv->clk))
|
||||
return PTR_ERR(priv->clk);
|
||||
|
||||
priv->chip.ops = &clps711x_pwm_ops;
|
||||
priv->chip.dev = &pdev->dev;
|
||||
priv->chip.npwm = 2;
|
||||
priv->chip.of_xlate = clps711x_pwm_xlate;
|
||||
priv->chip.of_pwm_n_cells = 1;
|
||||
chip->ops = &clps711x_pwm_ops;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &priv->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
|
||||
|
@ -26,17 +26,15 @@
|
||||
|
||||
/**
|
||||
* struct crystalcove_pwm - Crystal Cove PWM controller
|
||||
* @chip: the abstract pwm_chip structure.
|
||||
* @regmap: the regmap from the parent device.
|
||||
*/
|
||||
struct crystalcove_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct crystalcove_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int crc_pwm_calc_clk_div(int period_ns)
|
||||
@ -55,7 +53,7 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
|
||||
struct device *dev = crc_pwm->chip.dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
int err;
|
||||
|
||||
if (state->period > PWM_MAX_PERIOD_NS) {
|
||||
@ -125,7 +123,7 @@ static int crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
|
||||
struct device *dev = crc_pwm->chip.dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
unsigned int clk_div, clk_div_reg, duty_cycle_reg;
|
||||
int error;
|
||||
|
||||
@ -160,22 +158,22 @@ static const struct pwm_ops crc_pwm_ops = {
|
||||
|
||||
static int crystalcove_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct crystalcove_pwm *crc_pwm;
|
||||
struct device *dev = pdev->dev.parent;
|
||||
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
|
||||
|
||||
crc_pwm = devm_kzalloc(&pdev->dev, sizeof(*crc_pwm), GFP_KERNEL);
|
||||
if (!crc_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*crc_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
crc_pwm = to_crc_pwm(chip);
|
||||
|
||||
crc_pwm->chip.dev = &pdev->dev;
|
||||
crc_pwm->chip.ops = &crc_pwm_ops;
|
||||
crc_pwm->chip.npwm = 1;
|
||||
chip->ops = &crc_pwm_ops;
|
||||
|
||||
/* get the PMIC regmap */
|
||||
crc_pwm->regmap = pmic->regmap;
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &crc_pwm->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
static struct platform_driver crystalcove_pwm_driver = {
|
||||
|
@ -19,13 +19,11 @@
|
||||
* struct cros_ec_pwm_device - Driver data for EC PWM
|
||||
*
|
||||
* @ec: Pointer to EC device
|
||||
* @chip: PWM controller chip
|
||||
* @use_pwm_type: Use PWM types instead of generic channels
|
||||
* @channel: array with per-channel data
|
||||
*/
|
||||
struct cros_ec_pwm_device {
|
||||
struct cros_ec_device *ec;
|
||||
struct pwm_chip chip;
|
||||
bool use_pwm_type;
|
||||
struct cros_ec_pwm *channel;
|
||||
};
|
||||
@ -40,7 +38,7 @@ struct cros_ec_pwm {
|
||||
|
||||
static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct cros_ec_pwm_device, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
|
||||
@ -93,9 +91,8 @@ static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
|
||||
return cros_ec_cmd_xfer_status(ec, msg);
|
||||
}
|
||||
|
||||
static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
|
||||
static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, bool use_pwm_type, u8 index)
|
||||
{
|
||||
struct cros_ec_device *ec = ec_pwm->ec;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
union {
|
||||
@ -115,7 +112,7 @@ static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
|
||||
msg->insize = sizeof(*resp);
|
||||
msg->outsize = sizeof(*params);
|
||||
|
||||
if (ec_pwm->use_pwm_type) {
|
||||
if (use_pwm_type) {
|
||||
ret = cros_ec_dt_type_to_pwm_type(index, ¶ms->pwm_type);
|
||||
if (ret) {
|
||||
dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
|
||||
@ -171,9 +168,9 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
|
||||
ret = cros_ec_pwm_get_duty(ec_pwm->ec, ec_pwm->use_pwm_type, pwm->hwpwm);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "error getting initial duty: %d\n", ret);
|
||||
dev_err(pwmchip_parent(chip), "error getting initial duty: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -226,13 +223,17 @@ static const struct pwm_ops cros_ec_pwm_ops = {
|
||||
* of PWMs it supports directly, so we have to read the pwm duty cycle for
|
||||
* subsequent channels until we get an error.
|
||||
*/
|
||||
static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
|
||||
static int cros_ec_num_pwms(struct cros_ec_device *ec)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/* The index field is only 8 bits */
|
||||
for (i = 0; i <= U8_MAX; i++) {
|
||||
ret = cros_ec_pwm_get_duty(ec_pwm, i);
|
||||
/*
|
||||
* Note that this function is only called when use_pwm_type is
|
||||
* false. With use_pwm_type == true the number of PWMs is fixed.
|
||||
*/
|
||||
ret = cros_ec_pwm_get_duty(ec, false, i);
|
||||
/*
|
||||
* We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
|
||||
* responses; everything else is treated as an error.
|
||||
@ -261,35 +262,35 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct cros_ec_pwm_device *ec_pwm;
|
||||
struct pwm_chip *chip;
|
||||
bool use_pwm_type = false;
|
||||
unsigned int npwm;
|
||||
int ret;
|
||||
|
||||
if (!ec)
|
||||
return dev_err_probe(dev, -EINVAL, "no parent EC device\n");
|
||||
|
||||
ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
|
||||
if (!ec_pwm)
|
||||
return -ENOMEM;
|
||||
chip = &ec_pwm->chip;
|
||||
ec_pwm->ec = ec;
|
||||
|
||||
if (of_device_is_compatible(np, "google,cros-ec-pwm-type"))
|
||||
ec_pwm->use_pwm_type = true;
|
||||
|
||||
/* PWM chip */
|
||||
chip->dev = dev;
|
||||
chip->ops = &cros_ec_pwm_ops;
|
||||
chip->of_xlate = cros_ec_pwm_xlate;
|
||||
chip->of_pwm_n_cells = 1;
|
||||
|
||||
if (ec_pwm->use_pwm_type) {
|
||||
chip->npwm = CROS_EC_PWM_DT_COUNT;
|
||||
if (of_device_is_compatible(np, "google,cros-ec-pwm-type")) {
|
||||
use_pwm_type = true;
|
||||
npwm = CROS_EC_PWM_DT_COUNT;
|
||||
} else {
|
||||
ret = cros_ec_num_pwms(ec_pwm);
|
||||
ret = cros_ec_num_pwms(ec);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Couldn't find PWMs\n");
|
||||
chip->npwm = ret;
|
||||
npwm = ret;
|
||||
}
|
||||
|
||||
chip = devm_pwmchip_alloc(dev, npwm, sizeof(*ec_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
ec_pwm = pwm_to_cros_ec_pwm(chip);
|
||||
ec_pwm->use_pwm_type = use_pwm_type;
|
||||
ec_pwm->ec = ec;
|
||||
|
||||
/* PWM chip */
|
||||
chip->ops = &cros_ec_pwm_ops;
|
||||
chip->of_xlate = cros_ec_pwm_xlate;
|
||||
|
||||
ec_pwm->channel = devm_kcalloc(dev, chip->npwm, sizeof(*ec_pwm->channel),
|
||||
GFP_KERNEL);
|
||||
if (!ec_pwm->channel)
|
||||
|
@ -105,12 +105,12 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (state->enabled) {
|
||||
if (!pwm->state.enabled)
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
return __dwc_pwm_configure_timer(dwc, pwm, state);
|
||||
} else {
|
||||
if (pwm->state.enabled) {
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
u64 duty, period;
|
||||
u32 ctrl, ld, ld2;
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm));
|
||||
ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
|
||||
@ -149,7 +149,7 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
state->period = period;
|
||||
state->duty_cycle = duty;
|
||||
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -159,21 +159,21 @@ static const struct pwm_ops dwc_pwm_ops = {
|
||||
.get_state = dwc_pwm_get_state,
|
||||
};
|
||||
|
||||
struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
|
||||
struct pwm_chip *dwc_pwm_alloc(struct device *dev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct dwc_pwm *dwc;
|
||||
|
||||
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||
if (!dwc)
|
||||
return NULL;
|
||||
chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(*dwc));
|
||||
if (IS_ERR(chip))
|
||||
return chip;
|
||||
dwc = to_dwc_pwm(chip);
|
||||
|
||||
dwc->clk_ns = 10;
|
||||
dwc->chip.dev = dev;
|
||||
dwc->chip.ops = &dwc_pwm_ops;
|
||||
dwc->chip.npwm = DWC_TIMERS_TOTAL;
|
||||
chip->ops = &dwc_pwm_ops;
|
||||
|
||||
dev_set_drvdata(dev, dwc);
|
||||
return dwc;
|
||||
dev_set_drvdata(dev, chip);
|
||||
return chip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc_pwm_alloc);
|
||||
|
||||
|
@ -25,39 +25,54 @@
|
||||
|
||||
#include "pwm-dwc.h"
|
||||
|
||||
/* Elkhart Lake */
|
||||
static const struct dwc_pwm_info ehl_pwm_info = {
|
||||
.nr = 2,
|
||||
.size = 0x1000,
|
||||
};
|
||||
|
||||
static int dwc_pwm_init_one(struct device *dev, void __iomem *base, unsigned int offset)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct dwc_pwm *dwc;
|
||||
|
||||
chip = dwc_pwm_alloc(dev);
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
dwc = to_dwc_pwm(chip);
|
||||
dwc->base = base + offset;
|
||||
|
||||
return devm_pwmchip_add(dev, chip);
|
||||
}
|
||||
|
||||
static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
const struct dwc_pwm_info *info;
|
||||
struct device *dev = &pci->dev;
|
||||
struct dwc_pwm *dwc;
|
||||
int ret;
|
||||
|
||||
dwc = dwc_pwm_alloc(dev);
|
||||
if (!dwc)
|
||||
return -ENOMEM;
|
||||
int i, ret;
|
||||
|
||||
ret = pcim_enable_device(pci);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable device (%pe)\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable device\n");
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwc->base = pcim_iomap_table(pci)[0];
|
||||
if (!dwc->base) {
|
||||
dev_err(dev, "Base address missing\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_pwmchip_add(dev, &dwc->chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dev_err_probe(dev, ret, "Failed to iomap PCI BAR\n");
|
||||
|
||||
info = (const struct dwc_pwm_info *)id->driver_data;
|
||||
|
||||
for (i = 0; i < info->nr; i++) {
|
||||
/*
|
||||
* No need to check for pcim_iomap_table() failure,
|
||||
* pcim_iomap_regions() already does it for us.
|
||||
*/
|
||||
ret = dwc_pwm_init_one(dev, pcim_iomap_table(pci)[0], i * info->size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_allow(dev);
|
||||
@ -73,14 +88,14 @@ static void dwc_pwm_remove(struct pci_dev *pci)
|
||||
|
||||
static int dwc_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
|
||||
struct dwc_pwm *dwc = pci_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
|
||||
if (dwc->chip.pwms[i].state.enabled) {
|
||||
if (chip->pwms[i].state.enabled) {
|
||||
dev_err(dev, "PWM %u in use by consumer (%s)\n",
|
||||
i, dwc->chip.pwms[i].label);
|
||||
i, chip->pwms[i].label);
|
||||
return -EBUSY;
|
||||
}
|
||||
dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i));
|
||||
@ -93,8 +108,8 @@ static int dwc_pwm_suspend(struct device *dev)
|
||||
|
||||
static int dwc_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
|
||||
struct dwc_pwm *dwc = pci_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
|
||||
@ -109,7 +124,7 @@ static int dwc_pwm_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
|
||||
|
||||
static const struct pci_device_id dwc_pwm_id_table[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x4bb7) }, /* Elkhart Lake */
|
||||
{ PCI_VDEVICE(INTEL, 0x4bb7), (kernel_ulong_t)&ehl_pwm_info },
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc_pwm_id_table);
|
||||
@ -120,7 +135,7 @@ static struct pci_driver dwc_pwm_driver = {
|
||||
.remove = dwc_pwm_remove,
|
||||
.id_table = dwc_pwm_id_table,
|
||||
.driver = {
|
||||
.pm = pm_ptr(&dwc_pwm_pm_ops),
|
||||
.pm = pm_sleep_ptr(&dwc_pwm_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,11 @@ MODULE_IMPORT_NS(dwc_pwm);
|
||||
#define DWC_TIM_CTRL_INT_MASK BIT(2)
|
||||
#define DWC_TIM_CTRL_PWM BIT(3)
|
||||
|
||||
struct dwc_pwm_info {
|
||||
unsigned int nr;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct dwc_pwm_ctx {
|
||||
u32 cnt;
|
||||
u32 cnt2;
|
||||
@ -40,12 +45,15 @@ struct dwc_pwm_ctx {
|
||||
};
|
||||
|
||||
struct dwc_pwm {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
unsigned int clk_ns;
|
||||
struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
|
||||
};
|
||||
#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip))
|
||||
|
||||
static inline struct dwc_pwm *to_dwc_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
|
||||
{
|
||||
@ -57,4 +65,4 @@ static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset)
|
||||
writel(value, dwc->base + offset);
|
||||
}
|
||||
|
||||
extern struct dwc_pwm *dwc_pwm_alloc(struct device *dev);
|
||||
extern struct pwm_chip *dwc_pwm_alloc(struct device *dev);
|
||||
|
@ -36,24 +36,23 @@
|
||||
struct ep93xx_pwm {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ep93xx_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(chip->dev);
|
||||
struct platform_device *pdev = to_platform_device(pwmchip_parent(chip));
|
||||
|
||||
return ep93xx_pwm_acquire_gpio(pdev);
|
||||
}
|
||||
|
||||
static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(chip->dev);
|
||||
struct platform_device *pdev = to_platform_device(pwmchip_parent(chip));
|
||||
|
||||
ep93xx_pwm_release_gpio(pdev);
|
||||
}
|
||||
@ -163,12 +162,14 @@ static const struct pwm_ops ep93xx_pwm_ops = {
|
||||
|
||||
static int ep93xx_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct ep93xx_pwm *ep93xx_pwm;
|
||||
int ret;
|
||||
|
||||
ep93xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_pwm), GFP_KERNEL);
|
||||
if (!ep93xx_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*ep93xx_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
ep93xx_pwm = to_ep93xx_pwm(chip);
|
||||
|
||||
ep93xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ep93xx_pwm->base))
|
||||
@ -178,11 +179,9 @@ static int ep93xx_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ep93xx_pwm->clk))
|
||||
return PTR_ERR(ep93xx_pwm->clk);
|
||||
|
||||
ep93xx_pwm->chip.dev = &pdev->dev;
|
||||
ep93xx_pwm->chip.ops = &ep93xx_pwm_ops;
|
||||
ep93xx_pwm->chip.npwm = 1;
|
||||
chip->ops = &ep93xx_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &ep93xx_pwm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -40,7 +40,6 @@ struct fsl_pwm_periodcfg {
|
||||
};
|
||||
|
||||
struct fsl_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
|
||||
@ -55,7 +54,7 @@ struct fsl_pwm_chip {
|
||||
|
||||
static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct fsl_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)
|
||||
@ -221,10 +220,11 @@ static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,
|
||||
return false;
|
||||
}
|
||||
|
||||
static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
|
||||
static int fsl_pwm_apply_config(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm,
|
||||
const struct pwm_state *newstate)
|
||||
{
|
||||
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
|
||||
unsigned int duty;
|
||||
u32 reg_polarity;
|
||||
|
||||
@ -232,7 +232,7 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
|
||||
bool do_write_period = false;
|
||||
|
||||
if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
|
||||
dev_err(fpc->chip.dev, "failed to calculate new period\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to calculate new period\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
|
||||
*/
|
||||
else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
|
||||
if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
|
||||
dev_err(fpc->chip.dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"Cannot change period for PWM %u, disable other PWMs first\n",
|
||||
pwm->hwpwm);
|
||||
return -EBUSY;
|
||||
@ -322,7 +322,7 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
goto end_mutex;
|
||||
}
|
||||
|
||||
ret = fsl_pwm_apply_config(fpc, pwm, newstate);
|
||||
ret = fsl_pwm_apply_config(chip, pwm, newstate);
|
||||
if (ret)
|
||||
goto end_mutex;
|
||||
|
||||
@ -392,18 +392,19 @@ static const struct regmap_config fsl_pwm_regmap_config = {
|
||||
|
||||
static int fsl_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct fsl_pwm_chip *fpc;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
|
||||
if (!fpc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 8, sizeof(*fpc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
fpc = to_fsl_chip(chip);
|
||||
|
||||
mutex_init(&fpc->lock);
|
||||
|
||||
fpc->soc = of_device_get_match_data(&pdev->dev);
|
||||
fpc->chip.dev = &pdev->dev;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
@ -422,16 +423,16 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
|
||||
}
|
||||
|
||||
fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix");
|
||||
fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(&pdev->dev, "ftm_fix");
|
||||
if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
|
||||
return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
|
||||
|
||||
fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext");
|
||||
fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(&pdev->dev, "ftm_ext");
|
||||
if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
|
||||
return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
|
||||
|
||||
fpc->clk[FSL_PWM_CLK_CNTEN] =
|
||||
devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en");
|
||||
devm_clk_get(&pdev->dev, "ftm_cnt_clk_en");
|
||||
if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
|
||||
return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
|
||||
|
||||
@ -443,17 +444,15 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(fpc->ipg_clk))
|
||||
fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];
|
||||
|
||||
chip->ops = &fsl_pwm_ops;
|
||||
|
||||
fpc->chip.ops = &fsl_pwm_ops;
|
||||
fpc->chip.npwm = 8;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &fpc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, fpc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return fsl_pwm_init(fpc);
|
||||
}
|
||||
@ -461,14 +460,15 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int fsl_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
|
||||
int i;
|
||||
|
||||
regcache_cache_only(fpc->regmap, true);
|
||||
regcache_mark_dirty(fpc->regmap);
|
||||
|
||||
for (i = 0; i < fpc->chip.npwm; i++) {
|
||||
struct pwm_device *pwm = &fpc->chip.pwms[i];
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
|
||||
continue;
|
||||
@ -487,11 +487,12 @@ static int fsl_pwm_suspend(struct device *dev)
|
||||
|
||||
static int fsl_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fpc->chip.npwm; i++) {
|
||||
struct pwm_device *pwm = &fpc->chip.pwms[i];
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
|
||||
continue;
|
||||
|
@ -33,7 +33,6 @@
|
||||
#define PWM_DUTY_MASK GENMASK(31, 0)
|
||||
|
||||
struct hibvt_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct reset_control *rstc;
|
||||
@ -65,7 +64,7 @@ static const struct hibvt_pwm_soc hi3559v100_soc_info = {
|
||||
|
||||
static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct hibvt_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
|
||||
@ -191,72 +190,71 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct hibvt_pwm_soc *soc =
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
struct hibvt_pwm_chip *pwm_chip;
|
||||
struct pwm_chip *chip;
|
||||
struct hibvt_pwm_chip *hi_pwm_chip;
|
||||
int ret, i;
|
||||
|
||||
pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
|
||||
if (pwm_chip == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*hi_pwm_chip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
hi_pwm_chip = to_hibvt_pwm_chip(chip);
|
||||
|
||||
pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwm_chip->clk)) {
|
||||
hi_pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(hi_pwm_chip->clk)) {
|
||||
dev_err(&pdev->dev, "getting clock failed with %ld\n",
|
||||
PTR_ERR(pwm_chip->clk));
|
||||
return PTR_ERR(pwm_chip->clk);
|
||||
PTR_ERR(hi_pwm_chip->clk));
|
||||
return PTR_ERR(hi_pwm_chip->clk);
|
||||
}
|
||||
|
||||
pwm_chip->chip.ops = &hibvt_pwm_ops;
|
||||
pwm_chip->chip.dev = &pdev->dev;
|
||||
pwm_chip->chip.npwm = soc->num_pwms;
|
||||
pwm_chip->soc = soc;
|
||||
chip->ops = &hibvt_pwm_ops;
|
||||
hi_pwm_chip->soc = soc;
|
||||
|
||||
pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pwm_chip->base))
|
||||
return PTR_ERR(pwm_chip->base);
|
||||
hi_pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hi_pwm_chip->base))
|
||||
return PTR_ERR(hi_pwm_chip->base);
|
||||
|
||||
ret = clk_prepare_enable(pwm_chip->clk);
|
||||
ret = clk_prepare_enable(hi_pwm_chip->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pwm_chip->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwm_chip->rstc)) {
|
||||
clk_disable_unprepare(pwm_chip->clk);
|
||||
return PTR_ERR(pwm_chip->rstc);
|
||||
hi_pwm_chip->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(hi_pwm_chip->rstc)) {
|
||||
clk_disable_unprepare(hi_pwm_chip->clk);
|
||||
return PTR_ERR(hi_pwm_chip->rstc);
|
||||
}
|
||||
|
||||
reset_control_assert(pwm_chip->rstc);
|
||||
reset_control_assert(hi_pwm_chip->rstc);
|
||||
msleep(30);
|
||||
reset_control_deassert(pwm_chip->rstc);
|
||||
reset_control_deassert(hi_pwm_chip->rstc);
|
||||
|
||||
ret = pwmchip_add(&pwm_chip->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(pwm_chip->clk);
|
||||
clk_disable_unprepare(hi_pwm_chip->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < pwm_chip->chip.npwm; i++) {
|
||||
hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(i),
|
||||
PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pwm_chip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hibvt_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hibvt_pwm_chip *pwm_chip;
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip);
|
||||
|
||||
pwm_chip = platform_get_drvdata(pdev);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
pwmchip_remove(&pwm_chip->chip);
|
||||
|
||||
reset_control_assert(pwm_chip->rstc);
|
||||
reset_control_assert(hi_pwm_chip->rstc);
|
||||
msleep(30);
|
||||
reset_control_deassert(pwm_chip->rstc);
|
||||
reset_control_deassert(hi_pwm_chip->rstc);
|
||||
|
||||
clk_disable_unprepare(pwm_chip->clk);
|
||||
clk_disable_unprepare(hi_pwm_chip->clk);
|
||||
}
|
||||
|
||||
static const struct of_device_id hibvt_pwm_of_match[] = {
|
||||
|
@ -59,8 +59,6 @@ struct img_pwm_soc_data {
|
||||
};
|
||||
|
||||
struct img_pwm_chip {
|
||||
struct device *dev;
|
||||
struct pwm_chip chip;
|
||||
struct clk *pwm_clk;
|
||||
struct clk *sys_clk;
|
||||
void __iomem *base;
|
||||
@ -74,7 +72,7 @@ struct img_pwm_chip {
|
||||
|
||||
static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct img_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline void img_pwm_writel(struct img_pwm_chip *imgchip,
|
||||
@ -99,7 +97,7 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (period_ns < imgchip->min_period_ns ||
|
||||
period_ns > imgchip->max_period_ns) {
|
||||
dev_err(chip->dev, "configured period not in range\n");
|
||||
dev_err(pwmchip_parent(chip), "configured period not in range\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
@ -120,14 +118,14 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
div = PWM_CTRL_CFG_SUB_DIV0_DIV1;
|
||||
timebase = DIV_ROUND_UP(mul, 512);
|
||||
} else {
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"failed to configure timebase steps/divider value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
|
||||
|
||||
ret = pm_runtime_resume_and_get(chip->dev);
|
||||
ret = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -141,8 +139,8 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
(timebase << PWM_CH_CFG_TMBASE_SHIFT);
|
||||
img_pwm_writel(imgchip, PWM_CH_CFG(pwm->hwpwm), val);
|
||||
|
||||
pm_runtime_mark_last_busy(chip->dev);
|
||||
pm_runtime_put_autosuspend(chip->dev);
|
||||
pm_runtime_mark_last_busy(pwmchip_parent(chip));
|
||||
pm_runtime_put_autosuspend(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -153,7 +151,7 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(chip->dev);
|
||||
ret = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -177,8 +175,8 @@ static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
val &= ~BIT(pwm->hwpwm);
|
||||
img_pwm_writel(imgchip, PWM_CTRL_CFG, val);
|
||||
|
||||
pm_runtime_mark_last_busy(chip->dev);
|
||||
pm_runtime_put_autosuspend(chip->dev);
|
||||
pm_runtime_mark_last_busy(pwmchip_parent(chip));
|
||||
pm_runtime_put_autosuspend(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -225,7 +223,8 @@ MODULE_DEVICE_TABLE(of, img_pwm_of_match);
|
||||
|
||||
static int img_pwm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
|
||||
|
||||
clk_disable_unprepare(imgchip->pwm_clk);
|
||||
clk_disable_unprepare(imgchip->sys_clk);
|
||||
@ -235,7 +234,8 @@ static int img_pwm_runtime_suspend(struct device *dev)
|
||||
|
||||
static int img_pwm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(imgchip->sys_clk);
|
||||
@ -259,13 +259,13 @@ static int img_pwm_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
u64 val;
|
||||
unsigned long clk_rate;
|
||||
struct pwm_chip *chip;
|
||||
struct img_pwm_chip *imgchip;
|
||||
|
||||
imgchip = devm_kzalloc(&pdev->dev, sizeof(*imgchip), GFP_KERNEL);
|
||||
if (!imgchip)
|
||||
return -ENOMEM;
|
||||
|
||||
imgchip->dev = &pdev->dev;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, IMG_PWM_NPWM, sizeof(*imgchip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
imgchip = to_img_pwm_chip(chip);
|
||||
|
||||
imgchip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(imgchip->base))
|
||||
@ -290,7 +290,7 @@ static int img_pwm_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(imgchip->pwm_clk);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, imgchip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
@ -317,11 +317,9 @@ static int img_pwm_probe(struct platform_device *pdev)
|
||||
do_div(val, clk_rate);
|
||||
imgchip->min_period_ns = val;
|
||||
|
||||
imgchip->chip.dev = &pdev->dev;
|
||||
imgchip->chip.ops = &img_pwm_ops;
|
||||
imgchip->chip.npwm = IMG_PWM_NPWM;
|
||||
chip->ops = &img_pwm_ops;
|
||||
|
||||
ret = pwmchip_add(&imgchip->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
|
||||
goto err_suspend;
|
||||
@ -340,19 +338,20 @@ err_pm_disable:
|
||||
|
||||
static void img_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct img_pwm_chip *imgchip = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
img_pwm_runtime_suspend(&pdev->dev);
|
||||
|
||||
pwmchip_remove(&imgchip->chip);
|
||||
pwmchip_remove(chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int img_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
|
||||
int i, ret;
|
||||
|
||||
if (pm_runtime_status_suspended(dev)) {
|
||||
@ -361,7 +360,7 @@ static int img_pwm_suspend(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < imgchip->chip.npwm; i++)
|
||||
for (i = 0; i < chip->npwm; i++)
|
||||
imgchip->suspend_ch_cfg[i] = img_pwm_readl(imgchip,
|
||||
PWM_CH_CFG(i));
|
||||
|
||||
@ -374,7 +373,8 @@ static int img_pwm_suspend(struct device *dev)
|
||||
|
||||
static int img_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@ -382,13 +382,13 @@ static int img_pwm_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < imgchip->chip.npwm; i++)
|
||||
for (i = 0; i < chip->npwm; i++)
|
||||
img_pwm_writel(imgchip, PWM_CH_CFG(i),
|
||||
imgchip->suspend_ch_cfg[i]);
|
||||
|
||||
img_pwm_writel(imgchip, PWM_CTRL_CFG, imgchip->suspend_ctrl_cfg);
|
||||
|
||||
for (i = 0; i < imgchip->chip.npwm; i++)
|
||||
for (i = 0; i < chip->npwm; i++)
|
||||
if (imgchip->suspend_ctrl_cfg & BIT(i))
|
||||
regmap_clear_bits(imgchip->periph_regs,
|
||||
PERIP_PWM_PDM_CONTROL,
|
||||
|
@ -57,7 +57,6 @@
|
||||
#define PWM_IMX_TPM_MOD_MOD GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
|
||||
|
||||
struct imx_tpm_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct mutex lock;
|
||||
@ -75,7 +74,7 @@ struct imx_tpm_pwm_param {
|
||||
static inline struct imx_tpm_pwm_chip *
|
||||
to_imx_tpm_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct imx_tpm_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -336,35 +335,42 @@ static const struct pwm_ops imx_tpm_pwm_ops = {
|
||||
|
||||
static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct imx_tpm_pwm_chip *tpm;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
unsigned int npwm;
|
||||
u32 val;
|
||||
|
||||
tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
|
||||
if (!tpm)
|
||||
return -ENOMEM;
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
|
||||
"failed to get PWM clock\n");
|
||||
|
||||
/* get number of channels */
|
||||
val = readl(base + PWM_IMX_TPM_PARAM);
|
||||
npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
|
||||
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*tpm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
tpm = to_imx_tpm_pwm_chip(chip);
|
||||
|
||||
platform_set_drvdata(pdev, tpm);
|
||||
|
||||
tpm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(tpm->base))
|
||||
return PTR_ERR(tpm->base);
|
||||
tpm->base = base;
|
||||
tpm->clk = clk;
|
||||
|
||||
tpm->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(tpm->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk),
|
||||
"failed to get PWM clock\n");
|
||||
|
||||
tpm->chip.dev = &pdev->dev;
|
||||
tpm->chip.ops = &imx_tpm_pwm_ops;
|
||||
|
||||
/* get number of channels */
|
||||
val = readl(tpm->base + PWM_IMX_TPM_PARAM);
|
||||
tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
|
||||
chip->ops = &imx_tpm_pwm_ops;
|
||||
|
||||
mutex_init(&tpm->lock);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &tpm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -28,10 +28,12 @@ struct pwm_imx1_chip {
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_per;
|
||||
void __iomem *mmio_base;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
#define to_pwm_imx1_chip(chip) container_of(chip, struct pwm_imx1_chip, chip)
|
||||
static inline struct pwm_imx1_chip *to_pwm_imx1_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int pwm_imx1_clk_prepare_enable(struct pwm_chip *chip)
|
||||
{
|
||||
@ -156,11 +158,13 @@ MODULE_DEVICE_TABLE(of, pwm_imx1_dt_ids);
|
||||
|
||||
static int pwm_imx1_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct pwm_imx1_chip *imx;
|
||||
|
||||
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
|
||||
if (!imx)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
imx = to_pwm_imx1_chip(chip);
|
||||
|
||||
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(imx->clk_ipg))
|
||||
@ -172,15 +176,13 @@ static int pwm_imx1_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per),
|
||||
"failed to get peripheral clock\n");
|
||||
|
||||
imx->chip.ops = &pwm_imx1_ops;
|
||||
imx->chip.dev = &pdev->dev;
|
||||
imx->chip.npwm = 1;
|
||||
chip->ops = &pwm_imx1_ops;
|
||||
|
||||
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(imx->mmio_base))
|
||||
return PTR_ERR(imx->mmio_base);
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &imx->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
static struct platform_driver pwm_imx1_driver = {
|
||||
|
@ -83,7 +83,6 @@ struct pwm_imx27_chip {
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_per;
|
||||
void __iomem *mmio_base;
|
||||
struct pwm_chip chip;
|
||||
|
||||
/*
|
||||
* The driver cannot read the current duty cycle from the hardware if
|
||||
@ -93,7 +92,10 @@ struct pwm_imx27_chip {
|
||||
unsigned int duty_cycle;
|
||||
};
|
||||
|
||||
#define to_pwm_imx27_chip(chip) container_of(chip, struct pwm_imx27_chip, chip)
|
||||
static inline struct pwm_imx27_chip *to_pwm_imx27_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
|
||||
{
|
||||
@ -145,7 +147,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip,
|
||||
state->polarity = PWM_POLARITY_INVERSED;
|
||||
break;
|
||||
default:
|
||||
dev_warn(chip->dev, "can't set polarity, output disconnected");
|
||||
dev_warn(pwmchip_parent(chip), "can't set polarity, output disconnected");
|
||||
}
|
||||
|
||||
prescaler = MX3_PWMCR_PRESCALER_GET(val);
|
||||
@ -177,7 +179,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip,
|
||||
static void pwm_imx27_sw_reset(struct pwm_chip *chip)
|
||||
{
|
||||
struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
|
||||
struct device *dev = chip->dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
int wait_count = 0;
|
||||
u32 cr;
|
||||
|
||||
@ -196,7 +198,7 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm)
|
||||
{
|
||||
struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
|
||||
struct device *dev = chip->dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
unsigned int period_ms;
|
||||
int fifoav;
|
||||
u32 sr;
|
||||
@ -204,8 +206,8 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
|
||||
sr = readl(imx->mmio_base + MX3_PWMSR);
|
||||
fifoav = FIELD_GET(MX3_PWMSR_FIFOAV, sr);
|
||||
if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) {
|
||||
period_ms = DIV_ROUND_UP_ULL(pwm_get_period(pwm),
|
||||
NSEC_PER_MSEC);
|
||||
period_ms = DIV_ROUND_UP_ULL(pwm->state.period,
|
||||
NSEC_PER_MSEC);
|
||||
msleep(period_ms);
|
||||
|
||||
sr = readl(imx->mmio_base + MX3_PWMSR);
|
||||
@ -219,14 +221,11 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
{
|
||||
unsigned long period_cycles, duty_cycles, prescale;
|
||||
struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
|
||||
struct pwm_state cstate;
|
||||
unsigned long long c;
|
||||
unsigned long long clkrate;
|
||||
int ret;
|
||||
u32 cr;
|
||||
|
||||
pwm_get_state(pwm, &cstate);
|
||||
|
||||
clkrate = clk_get_rate(imx->clk_per);
|
||||
c = clkrate * state->period;
|
||||
|
||||
@ -254,7 +253,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* Wait for a free FIFO slot if the PWM is already enabled, and flush
|
||||
* the FIFO if the PWM was disabled and is about to be enabled.
|
||||
*/
|
||||
if (cstate.enabled) {
|
||||
if (pwm->state.enabled) {
|
||||
pwm_imx27_wait_fifo_slot(chip, pwm);
|
||||
} else {
|
||||
ret = pwm_imx27_clk_prepare_enable(imx);
|
||||
@ -306,13 +305,15 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
|
||||
|
||||
static int pwm_imx27_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct pwm_imx27_chip *imx;
|
||||
int ret;
|
||||
u32 pwmcr;
|
||||
|
||||
imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
|
||||
if (imx == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
imx = to_pwm_imx27_chip(chip);
|
||||
|
||||
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(imx->clk_ipg))
|
||||
@ -324,9 +325,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per),
|
||||
"failed to get peripheral clock\n");
|
||||
|
||||
imx->chip.ops = &pwm_imx27_ops;
|
||||
imx->chip.dev = &pdev->dev;
|
||||
imx->chip.npwm = 1;
|
||||
chip->ops = &pwm_imx27_ops;
|
||||
|
||||
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(imx->mmio_base))
|
||||
@ -341,7 +340,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
|
||||
if (!(pwmcr & MX3_PWMCR_EN))
|
||||
pwm_imx27_clk_disable_unprepare(imx);
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &imx->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
static struct platform_driver imx_pwm_driver = {
|
||||
|
@ -42,14 +42,13 @@
|
||||
#define LGM_PWM_PERIOD_2WIRE_NS (40 * NSEC_PER_MSEC)
|
||||
|
||||
struct lgm_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
u32 period;
|
||||
};
|
||||
|
||||
static inline struct lgm_pwm_chip *to_lgm_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct lgm_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int lgm_pwm_enable(struct pwm_chip *chip, bool enable)
|
||||
@ -168,14 +167,16 @@ static int lgm_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct reset_control *rst;
|
||||
struct pwm_chip *chip;
|
||||
struct lgm_pwm_chip *pc;
|
||||
void __iomem *io_base;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, 1, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_lgm_pwm_chip(chip);
|
||||
|
||||
io_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(io_base))
|
||||
@ -203,13 +204,11 @@ static int lgm_pwm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "cannot deassert reset control\n");
|
||||
|
||||
pc->chip.dev = dev;
|
||||
pc->chip.ops = &lgm_pwm_ops;
|
||||
pc->chip.npwm = 1;
|
||||
chip->ops = &lgm_pwm_ops;
|
||||
|
||||
lgm_pwm_init(pc);
|
||||
|
||||
ret = devm_pwmchip_add(dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -34,12 +34,17 @@
|
||||
|
||||
struct iqs620_pwm_private {
|
||||
struct iqs62x_core *iqs62x;
|
||||
struct pwm_chip chip;
|
||||
struct device *dev;
|
||||
struct notifier_block notifier;
|
||||
struct mutex lock;
|
||||
unsigned int duty_scale;
|
||||
};
|
||||
|
||||
static inline struct iqs620_pwm_private *iqs620_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm,
|
||||
unsigned int duty_scale)
|
||||
{
|
||||
@ -73,7 +78,7 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (state->period < IQS620_PWM_PERIOD_NS)
|
||||
return -EINVAL;
|
||||
|
||||
iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
|
||||
iqs620_pwm = iqs620_pwm_from_chip(chip);
|
||||
|
||||
/*
|
||||
* The duty cycle generated by the device is calculated as follows:
|
||||
@ -109,7 +114,7 @@ static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
{
|
||||
struct iqs620_pwm_private *iqs620_pwm;
|
||||
|
||||
iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
|
||||
iqs620_pwm = iqs620_pwm_from_chip(chip);
|
||||
|
||||
mutex_lock(&iqs620_pwm->lock);
|
||||
|
||||
@ -155,7 +160,7 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier,
|
||||
mutex_unlock(&iqs620_pwm->lock);
|
||||
|
||||
if (ret) {
|
||||
dev_err(iqs620_pwm->chip.dev,
|
||||
dev_err(iqs620_pwm->dev,
|
||||
"Failed to re-initialize device: %d\n", ret);
|
||||
return NOTIFY_BAD;
|
||||
}
|
||||
@ -176,21 +181,24 @@ static void iqs620_pwm_notifier_unregister(void *context)
|
||||
ret = blocking_notifier_chain_unregister(&iqs620_pwm->iqs62x->nh,
|
||||
&iqs620_pwm->notifier);
|
||||
if (ret)
|
||||
dev_err(iqs620_pwm->chip.dev,
|
||||
dev_err(iqs620_pwm->dev,
|
||||
"Failed to unregister notifier: %d\n", ret);
|
||||
}
|
||||
|
||||
static int iqs620_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pwm_chip *chip;
|
||||
struct iqs620_pwm_private *iqs620_pwm;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
iqs620_pwm = devm_kzalloc(&pdev->dev, sizeof(*iqs620_pwm), GFP_KERNEL);
|
||||
if (!iqs620_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*iqs620_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
iqs620_pwm = iqs620_pwm_from_chip(chip);
|
||||
iqs620_pwm->dev = &pdev->dev;
|
||||
iqs620_pwm->iqs62x = iqs62x;
|
||||
|
||||
ret = regmap_read(iqs62x->regmap, IQS620_PWR_SETTINGS, &val);
|
||||
@ -205,9 +213,7 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
|
||||
iqs620_pwm->duty_scale = val + 1;
|
||||
}
|
||||
|
||||
iqs620_pwm->chip.dev = &pdev->dev;
|
||||
iqs620_pwm->chip.ops = &iqs620_pwm_ops;
|
||||
iqs620_pwm->chip.npwm = 1;
|
||||
chip->ops = &iqs620_pwm_ops;
|
||||
|
||||
mutex_init(&iqs620_pwm->lock);
|
||||
|
||||
@ -225,7 +231,7 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &iqs620_pwm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to add device: %d\n", ret);
|
||||
|
||||
|
@ -25,23 +25,21 @@ struct soc_info {
|
||||
};
|
||||
|
||||
struct jz4740_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *map;
|
||||
struct clk *clk[];
|
||||
};
|
||||
|
||||
static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct jz4740_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
|
||||
unsigned int channel)
|
||||
static bool jz4740_pwm_can_use_chn(struct pwm_chip *chip, unsigned int channel)
|
||||
{
|
||||
/* Enable all TCU channels for PWM use by default except channels 0/1 */
|
||||
u32 pwm_channels_mask = GENMASK(jz->chip.npwm - 1, 2);
|
||||
u32 pwm_channels_mask = GENMASK(chip->npwm - 1, 2);
|
||||
|
||||
device_property_read_u32(jz->chip.dev->parent,
|
||||
device_property_read_u32(pwmchip_parent(chip)->parent,
|
||||
"ingenic,pwm-channels-mask",
|
||||
&pwm_channels_mask);
|
||||
|
||||
@ -55,14 +53,15 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
char name[16];
|
||||
int err;
|
||||
|
||||
if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm))
|
||||
if (!jz4740_pwm_can_use_chn(chip, pwm->hwpwm))
|
||||
return -EBUSY;
|
||||
|
||||
snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
|
||||
|
||||
clk = clk_get(chip->dev, name);
|
||||
clk = clk_get(pwmchip_parent(chip), name);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(chip->dev, "error %pe: Failed to get clock\n", clk);
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"error %pe: Failed to get clock\n", clk);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
@ -150,7 +149,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
*/
|
||||
rate = clk_round_rate(clk, tmp);
|
||||
if (rate < 0) {
|
||||
dev_err(chip->dev, "Unable to round rate: %ld\n", rate);
|
||||
dev_err(pwmchip_parent(chip), "Unable to round rate: %ld\n", rate);
|
||||
return rate;
|
||||
}
|
||||
|
||||
@ -171,7 +170,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
err = clk_set_rate(clk, rate);
|
||||
if (err) {
|
||||
dev_err(chip->dev, "Unable to set rate: %d\n", err);
|
||||
dev_err(pwmchip_parent(chip), "Unable to set rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -224,6 +223,7 @@ static const struct pwm_ops jz4740_pwm_ops = {
|
||||
static int jz4740_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_chip *chip;
|
||||
struct jz4740_pwm_chip *jz;
|
||||
const struct soc_info *info;
|
||||
|
||||
@ -231,10 +231,10 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
jz = devm_kzalloc(dev, struct_size(jz, clk, info->num_pwms),
|
||||
GFP_KERNEL);
|
||||
if (!jz)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, info->num_pwms, struct_size(jz, clk, info->num_pwms));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
jz = to_jz4740(chip);
|
||||
|
||||
jz->map = device_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(jz->map)) {
|
||||
@ -242,11 +242,9 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(jz->map);
|
||||
}
|
||||
|
||||
jz->chip.dev = dev;
|
||||
jz->chip.ops = &jz4740_pwm_ops;
|
||||
jz->chip.npwm = info->num_pwms;
|
||||
chip->ops = &jz4740_pwm_ops;
|
||||
|
||||
return devm_pwmchip_add(dev, &jz->chip);
|
||||
return devm_pwmchip_add(dev, chip);
|
||||
}
|
||||
|
||||
static const struct soc_info jz4740_soc_info = {
|
||||
|
@ -36,7 +36,6 @@
|
||||
#define KMB_PWM_HIGHLOW_OFFSET(ch) (0x20 + 4 * (ch))
|
||||
|
||||
struct keembay_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
@ -44,7 +43,7 @@ struct keembay_pwm {
|
||||
|
||||
static inline struct keembay_pwm *to_keembay_pwm_dev(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct keembay_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void keembay_clk_unprepare(void *data)
|
||||
@ -185,12 +184,14 @@ static const struct pwm_ops keembay_pwm_ops = {
|
||||
static int keembay_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_chip *chip;
|
||||
struct keembay_pwm *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, KMB_TOTAL_PWM_CHANNELS, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = to_keembay_pwm_dev(chip);
|
||||
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk))
|
||||
@ -204,11 +205,9 @@ static int keembay_pwm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &keembay_pwm_ops;
|
||||
priv->chip.npwm = KMB_TOTAL_PWM_CHANNELS;
|
||||
chip->ops = &keembay_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(dev, &priv->chip);
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to add PWM chip\n");
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#define LP3943_MAX_PERIOD 1600000
|
||||
|
||||
struct lp3943_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct lp3943 *lp3943;
|
||||
struct lp3943_platform_data *pdata;
|
||||
struct lp3943_pwm_map pwm_map[LP3943_NUM_PWMS];
|
||||
@ -28,7 +27,7 @@ struct lp3943_pwm {
|
||||
|
||||
static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct lp3943_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static struct lp3943_pwm_map *
|
||||
@ -273,12 +272,14 @@ static int lp3943_pwm_parse_dt(struct device *dev,
|
||||
static int lp3943_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pwm_chip *chip;
|
||||
struct lp3943_pwm *lp3943_pwm;
|
||||
int ret;
|
||||
|
||||
lp3943_pwm = devm_kzalloc(&pdev->dev, sizeof(*lp3943_pwm), GFP_KERNEL);
|
||||
if (!lp3943_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, LP3943_NUM_PWMS, sizeof(*lp3943_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
lp3943_pwm = to_lp3943_pwm(chip);
|
||||
|
||||
lp3943_pwm->pdata = lp3943->pdata;
|
||||
if (!lp3943_pwm->pdata) {
|
||||
@ -292,11 +293,9 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
lp3943_pwm->lp3943 = lp3943;
|
||||
lp3943_pwm->chip.dev = &pdev->dev;
|
||||
lp3943_pwm->chip.ops = &lp3943_pwm_ops;
|
||||
lp3943_pwm->chip.npwm = LP3943_NUM_PWMS;
|
||||
chip->ops = &lp3943_pwm_ops;
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &lp3943_pwm->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@ -92,8 +92,6 @@ struct lpc18xx_pwm_data {
|
||||
};
|
||||
|
||||
struct lpc18xx_pwm_chip {
|
||||
struct device *dev;
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *pwm_clk;
|
||||
unsigned long clk_rate;
|
||||
@ -110,7 +108,7 @@ struct lpc18xx_pwm_chip {
|
||||
static inline struct lpc18xx_pwm_chip *
|
||||
to_lpc18xx_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct lpc18xx_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
|
||||
@ -198,7 +196,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (period_ns < lpc18xx_pwm->min_period_ns ||
|
||||
period_ns > lpc18xx_pwm->max_period_ns) {
|
||||
dev_err(chip->dev, "period %d not in range\n", period_ns);
|
||||
dev_err(pwmchip_parent(chip), "period %d not in range\n", period_ns);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
@ -214,7 +212,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
*/
|
||||
if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
|
||||
lpc18xx_pwm->period_ns) {
|
||||
dev_err(chip->dev, "conflicting period requested for PWM %u\n",
|
||||
dev_err(pwmchip_parent(chip), "conflicting period requested for PWM %u\n",
|
||||
pwm->hwpwm);
|
||||
mutex_unlock(&lpc18xx_pwm->period_lock);
|
||||
return -EBUSY;
|
||||
@ -289,7 +287,7 @@ static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
LPC18XX_PWM_EVENT_MAX);
|
||||
|
||||
if (event >= LPC18XX_PWM_EVENT_MAX) {
|
||||
dev_err(lpc18xx_pwm->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"maximum number of simultaneous channels reached\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -349,16 +347,15 @@ MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
|
||||
|
||||
static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct lpc18xx_pwm_chip *lpc18xx_pwm;
|
||||
int ret;
|
||||
u64 val;
|
||||
|
||||
lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
|
||||
GFP_KERNEL);
|
||||
if (!lpc18xx_pwm)
|
||||
return -ENOMEM;
|
||||
|
||||
lpc18xx_pwm->dev = &pdev->dev;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, LPC18XX_NUM_PWMS, sizeof(*lpc18xx_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
|
||||
|
||||
lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(lpc18xx_pwm->base))
|
||||
@ -389,9 +386,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
|
||||
lpc18xx_pwm->clk_rate);
|
||||
|
||||
lpc18xx_pwm->chip.dev = &pdev->dev;
|
||||
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
|
||||
lpc18xx_pwm->chip.npwm = LPC18XX_NUM_PWMS;
|
||||
chip->ops = &lpc18xx_pwm_ops;
|
||||
|
||||
/* SCT counter must be in unify (32 bit) mode */
|
||||
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
|
||||
@ -423,21 +418,22 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
val |= LPC18XX_PWM_PRE(0);
|
||||
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
|
||||
|
||||
ret = pwmchip_add(&lpc18xx_pwm->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n");
|
||||
|
||||
platform_set_drvdata(pdev, lpc18xx_pwm);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpc18xx_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
|
||||
u32 val;
|
||||
|
||||
pwmchip_remove(&lpc18xx_pwm->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
|
||||
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct lpc32xx_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
};
|
||||
@ -23,8 +22,10 @@ struct lpc32xx_pwm_chip {
|
||||
#define PWM_ENABLE BIT(31)
|
||||
#define PWM_PIN_LEVEL BIT(30)
|
||||
|
||||
#define to_lpc32xx_pwm_chip(_chip) \
|
||||
container_of(_chip, struct lpc32xx_pwm_chip, chip)
|
||||
static inline struct lpc32xx_pwm_chip *to_lpc32xx_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
@ -119,13 +120,15 @@ static const struct pwm_ops lpc32xx_pwm_ops = {
|
||||
|
||||
static int lpc32xx_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct lpc32xx_pwm_chip *lpc32xx;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL);
|
||||
if (!lpc32xx)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*lpc32xx));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
lpc32xx = to_lpc32xx_pwm_chip(chip);
|
||||
|
||||
lpc32xx->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(lpc32xx->base))
|
||||
@ -135,16 +138,14 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(lpc32xx->clk))
|
||||
return PTR_ERR(lpc32xx->clk);
|
||||
|
||||
lpc32xx->chip.dev = &pdev->dev;
|
||||
lpc32xx->chip.ops = &lpc32xx_pwm_ops;
|
||||
lpc32xx->chip.npwm = 1;
|
||||
chip->ops = &lpc32xx_pwm_ops;
|
||||
|
||||
/* If PWM is disabled, configure the output to the default value */
|
||||
val = readl(lpc32xx->base);
|
||||
val &= ~PWM_PIN_LEVEL;
|
||||
writel(val, lpc32xx->base);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &lpc32xx->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret);
|
||||
return ret;
|
||||
|
@ -18,7 +18,7 @@ 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;
|
||||
struct pwm_chip *chip;
|
||||
int err;
|
||||
|
||||
err = pcim_enable_device(pdev);
|
||||
@ -30,11 +30,9 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
|
||||
return err;
|
||||
|
||||
info = (struct pwm_lpss_boardinfo *)id->driver_data;
|
||||
lpwm = devm_pwm_lpss_probe(&pdev->dev, pcim_iomap_table(pdev)[0], info);
|
||||
if (IS_ERR(lpwm))
|
||||
return PTR_ERR(lpwm);
|
||||
|
||||
pci_set_drvdata(pdev, lpwm);
|
||||
chip = devm_pwm_lpss_probe(&pdev->dev, pcim_iomap_table(pdev)[0], info);
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
@ -20,7 +20,7 @@
|
||||
static int pwm_lpss_probe_platform(struct platform_device *pdev)
|
||||
{
|
||||
const struct pwm_lpss_boardinfo *info;
|
||||
struct pwm_lpss_chip *lpwm;
|
||||
struct pwm_chip *chip;
|
||||
void __iomem *base;
|
||||
|
||||
info = device_get_match_data(&pdev->dev);
|
||||
@ -31,11 +31,9 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
lpwm = devm_pwm_lpss_probe(&pdev->dev, base, info);
|
||||
if (IS_ERR(lpwm))
|
||||
return PTR_ERR(lpwm);
|
||||
|
||||
platform_set_drvdata(pdev, lpwm);
|
||||
chip = devm_pwm_lpss_probe(&pdev->dev, base, info);
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
/*
|
||||
* On Cherry Trail devices the GFX0._PS0 AML checks if the controller
|
||||
|
@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(pwm_lpss_tng_info);
|
||||
|
||||
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pwm_lpss_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 pwm_lpss_read(const struct pwm_device *pwm)
|
||||
@ -106,7 +106,7 @@ static int pwm_lpss_wait_for_update(struct pwm_device *pwm)
|
||||
*/
|
||||
err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms);
|
||||
if (err)
|
||||
dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n");
|
||||
dev_err(pwmchip_parent(pwm->chip), "PWM_SW_UPDATE was not cleared\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -114,7 +114,7 @@ static int pwm_lpss_wait_for_update(struct pwm_device *pwm)
|
||||
static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
|
||||
{
|
||||
if (pwm_lpss_read(pwm) & PWM_SW_UPDATE) {
|
||||
dev_err(pwm->chip->dev, "PWM_SW_UPDATE is still set, skipping update\n");
|
||||
dev_err(pwmchip_parent(pwm->chip), "PWM_SW_UPDATE is still set, skipping update\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@ -190,16 +190,16 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (state->enabled) {
|
||||
if (!pwm_is_enabled(pwm)) {
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
|
||||
if (ret)
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
} else {
|
||||
ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
|
||||
}
|
||||
} else if (pwm_is_enabled(pwm)) {
|
||||
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -213,7 +213,7 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long long base_unit, freq, on_time_div;
|
||||
u32 ctrl;
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
base_unit_range = BIT(lpwm->info->base_unit_bits);
|
||||
|
||||
@ -235,7 +235,7 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
state->enabled = !!(ctrl & PWM_ENABLE);
|
||||
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -245,10 +245,11 @@ static const struct pwm_ops pwm_lpss_ops = {
|
||||
.get_state = pwm_lpss_get_state,
|
||||
};
|
||||
|
||||
struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
|
||||
const struct pwm_lpss_boardinfo *info)
|
||||
struct pwm_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
|
||||
const struct pwm_lpss_boardinfo *info)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm;
|
||||
struct pwm_chip *chip;
|
||||
unsigned long c;
|
||||
int i, ret;
|
||||
u32 ctrl;
|
||||
@ -256,9 +257,10 @@ struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base
|
||||
if (WARN_ON(info->npwm > LPSS_MAX_PWMS))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
|
||||
if (!lpwm)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
chip = devm_pwmchip_alloc(dev, info->npwm, sizeof(*lpwm));
|
||||
if (IS_ERR(chip))
|
||||
return chip;
|
||||
lpwm = to_lpwm(chip);
|
||||
|
||||
lpwm->regs = base;
|
||||
lpwm->info = info;
|
||||
@ -267,23 +269,21 @@ struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base
|
||||
if (!c)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
lpwm->chip.dev = dev;
|
||||
lpwm->chip.ops = &pwm_lpss_ops;
|
||||
lpwm->chip.npwm = info->npwm;
|
||||
chip->ops = &pwm_lpss_ops;
|
||||
|
||||
ret = devm_pwmchip_add(dev, &lpwm->chip);
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add PWM chip: %d\n", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < lpwm->info->npwm; i++) {
|
||||
ctrl = pwm_lpss_read(&lpwm->chip.pwms[i]);
|
||||
ctrl = pwm_lpss_read(&chip->pwms[i]);
|
||||
if (ctrl & PWM_ENABLE)
|
||||
pm_runtime_get(dev);
|
||||
}
|
||||
|
||||
return lpwm;
|
||||
return chip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pwm_lpss_probe);
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#define LPSS_MAX_PWMS 4
|
||||
|
||||
struct pwm_lpss_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *regs;
|
||||
const struct pwm_lpss_boardinfo *info;
|
||||
};
|
||||
|
@ -42,16 +42,13 @@ struct pwm_mediatek_of_data {
|
||||
|
||||
/**
|
||||
* struct pwm_mediatek_chip - struct representing PWM chip
|
||||
* @chip: linux PWM chip representation
|
||||
* @regs: base address of PWM chip
|
||||
* @clk_top: the top clock generator
|
||||
* @clk_main: the clock used by PWM core
|
||||
* @clk_pwms: the clock used by each PWM channel
|
||||
* @clk_freq: the fix clock frequency of legacy MIPS SoC
|
||||
* @soc: pointer to chip's platform data
|
||||
*/
|
||||
struct pwm_mediatek_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *regs;
|
||||
struct clk *clk_top;
|
||||
struct clk *clk_main;
|
||||
@ -70,7 +67,7 @@ static const unsigned int mtk_pwm_reg_offset_v2[] = {
|
||||
static inline struct pwm_mediatek_chip *
|
||||
to_pwm_mediatek_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pwm_mediatek_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int pwm_mediatek_clk_enable(struct pwm_chip *chip,
|
||||
@ -150,7 +147,7 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (clkdiv > PWM_CLK_DIV_MAX) {
|
||||
pwm_mediatek_clk_disable(chip, pwm);
|
||||
dev_err(chip->dev, "period of %d ns not supported\n", period_ns);
|
||||
dev_err(pwmchip_parent(chip), "period of %d ns not supported\n", period_ns);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -233,21 +230,26 @@ static const struct pwm_ops pwm_mediatek_ops = {
|
||||
|
||||
static int pwm_mediatek_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct pwm_mediatek_chip *pc;
|
||||
const struct pwm_mediatek_of_data *soc;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
pc->soc = of_device_get_match_data(&pdev->dev);
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_pwm_mediatek_chip(chip);
|
||||
|
||||
pc->soc = soc;
|
||||
|
||||
pc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->regs))
|
||||
return PTR_ERR(pc->regs);
|
||||
|
||||
pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms,
|
||||
pc->clk_pwms = devm_kmalloc_array(&pdev->dev, soc->num_pwms,
|
||||
sizeof(*pc->clk_pwms), GFP_KERNEL);
|
||||
if (!pc->clk_pwms)
|
||||
return -ENOMEM;
|
||||
@ -262,7 +264,7 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main),
|
||||
"Failed to get main clock\n");
|
||||
|
||||
for (i = 0; i < pc->soc->num_pwms; i++) {
|
||||
for (i = 0; i < soc->num_pwms; i++) {
|
||||
char name[8];
|
||||
|
||||
snprintf(name, sizeof(name), "pwm%d", i + 1);
|
||||
@ -273,11 +275,9 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
|
||||
"Failed to get %s clock\n", name);
|
||||
}
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &pwm_mediatek_ops;
|
||||
pc->chip.npwm = pc->soc->num_pwms;
|
||||
chip->ops = &pwm_mediatek_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
|
||||
@ -340,6 +340,13 @@ static const struct pwm_mediatek_of_data mt7986_pwm_data = {
|
||||
.reg_offset = mtk_pwm_reg_offset_v1,
|
||||
};
|
||||
|
||||
static const struct pwm_mediatek_of_data mt7988_pwm_data = {
|
||||
.num_pwms = 8,
|
||||
.pwm45_fixup = false,
|
||||
.has_ck_26m_sel = false,
|
||||
.reg_offset = mtk_pwm_reg_offset_v2,
|
||||
};
|
||||
|
||||
static const struct pwm_mediatek_of_data mt8183_pwm_data = {
|
||||
.num_pwms = 4,
|
||||
.pwm45_fixup = false,
|
||||
@ -370,6 +377,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
|
||||
{ .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
|
||||
{ .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data },
|
||||
{ .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
|
||||
{ .compatible = "mediatek,mt7988-pwm", .data = &mt7988_pwm_data },
|
||||
{ .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data },
|
||||
{ .compatible = "mediatek,mt8365-pwm", .data = &mt8365_pwm_data },
|
||||
{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
|
||||
|
@ -60,7 +60,7 @@
|
||||
#define MISC_A_EN BIT(0)
|
||||
|
||||
#define MESON_NUM_PWMS 2
|
||||
#define MESON_MAX_MUX_PARENTS 4
|
||||
#define MESON_NUM_MUX_PARENTS 4
|
||||
|
||||
static struct meson_pwm_channel_data {
|
||||
u8 reg_offset;
|
||||
@ -97,12 +97,10 @@ struct meson_pwm_channel {
|
||||
};
|
||||
|
||||
struct meson_pwm_data {
|
||||
const char * const *parent_names;
|
||||
unsigned int num_parents;
|
||||
const char *const parent_names[MESON_NUM_MUX_PARENTS];
|
||||
};
|
||||
|
||||
struct meson_pwm {
|
||||
struct pwm_chip chip;
|
||||
const struct meson_pwm_data *data;
|
||||
struct meson_pwm_channel channels[MESON_NUM_PWMS];
|
||||
void __iomem *base;
|
||||
@ -115,14 +113,14 @@ struct meson_pwm {
|
||||
|
||||
static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct meson_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct meson_pwm *meson = to_meson_pwm(chip);
|
||||
struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
|
||||
struct device *dev = chip->dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(channel->clk);
|
||||
@ -143,9 +141,10 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
clk_disable_unprepare(channel->clk);
|
||||
}
|
||||
|
||||
static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
|
||||
static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct meson_pwm *meson = to_meson_pwm(chip);
|
||||
struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
|
||||
unsigned int cnt, duty_cnt;
|
||||
unsigned long fin_freq;
|
||||
@ -169,19 +168,19 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
|
||||
|
||||
fin_freq = clk_round_rate(channel->clk, freq);
|
||||
if (fin_freq == 0) {
|
||||
dev_err(meson->chip.dev, "invalid source clock frequency\n");
|
||||
dev_err(pwmchip_parent(chip), "invalid source clock frequency\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
|
||||
dev_dbg(pwmchip_parent(chip), "fin_freq: %lu Hz\n", fin_freq);
|
||||
|
||||
cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
|
||||
if (cnt > 0xffff) {
|
||||
dev_err(meson->chip.dev, "unable to get period cnt\n");
|
||||
dev_err(pwmchip_parent(chip), "unable to get period cnt\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt);
|
||||
dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u\n", period, cnt);
|
||||
|
||||
if (duty == period) {
|
||||
channel->hi = cnt;
|
||||
@ -192,7 +191,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
|
||||
} else {
|
||||
duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
|
||||
|
||||
dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
|
||||
dev_dbg(pwmchip_parent(chip), "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
|
||||
|
||||
channel->hi = duty_cnt;
|
||||
channel->lo = cnt - duty_cnt;
|
||||
@ -203,8 +202,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
|
||||
static void meson_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct meson_pwm *meson = to_meson_pwm(chip);
|
||||
struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
|
||||
struct meson_pwm_channel_data *channel_data;
|
||||
unsigned long flags;
|
||||
@ -215,7 +215,7 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
|
||||
|
||||
err = clk_set_rate(channel->clk, channel->rate);
|
||||
if (err)
|
||||
dev_err(meson->chip.dev, "setting clock rate failed\n");
|
||||
dev_err(pwmchip_parent(chip), "setting clock rate failed\n");
|
||||
|
||||
spin_lock_irqsave(&meson->lock, flags);
|
||||
|
||||
@ -230,8 +230,9 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
|
||||
spin_unlock_irqrestore(&meson->lock, flags);
|
||||
}
|
||||
|
||||
static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
|
||||
static void meson_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct meson_pwm *meson = to_meson_pwm(chip);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
||||
@ -269,16 +270,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
channel->hi = ~0;
|
||||
channel->lo = 0;
|
||||
|
||||
meson_pwm_enable(meson, pwm);
|
||||
meson_pwm_enable(chip, pwm);
|
||||
} else {
|
||||
meson_pwm_disable(meson, pwm);
|
||||
meson_pwm_disable(chip, pwm);
|
||||
}
|
||||
} else {
|
||||
err = meson_pwm_calc(meson, pwm, state);
|
||||
err = meson_pwm_calc(chip, pwm, state);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
meson_pwm_enable(meson, pwm);
|
||||
meson_pwm_enable(chip, pwm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -337,62 +338,32 @@ static const struct pwm_ops meson_pwm_ops = {
|
||||
.get_state = meson_pwm_get_state,
|
||||
};
|
||||
|
||||
static const char * const pwm_meson8b_parent_names[] = {
|
||||
"xtal", NULL, "fclk_div4", "fclk_div3"
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_meson8b_data = {
|
||||
.parent_names = pwm_meson8b_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_meson8b_parent_names),
|
||||
.parent_names = { "xtal", NULL, "fclk_div4", "fclk_div3" },
|
||||
};
|
||||
|
||||
/*
|
||||
* Only the 2 first inputs of the GXBB AO PWMs are valid
|
||||
* The last 2 are grounded
|
||||
*/
|
||||
static const char * const pwm_gxbb_ao_parent_names[] = {
|
||||
"xtal", "clk81"
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_gxbb_ao_data = {
|
||||
.parent_names = pwm_gxbb_ao_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_names),
|
||||
};
|
||||
|
||||
static const char * const pwm_axg_ee_parent_names[] = {
|
||||
"xtal", "fclk_div5", "fclk_div4", "fclk_div3"
|
||||
.parent_names = { "xtal", "clk81", NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_axg_ee_data = {
|
||||
.parent_names = pwm_axg_ee_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_axg_ee_parent_names),
|
||||
};
|
||||
|
||||
static const char * const pwm_axg_ao_parent_names[] = {
|
||||
"xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5"
|
||||
.parent_names = { "xtal", "fclk_div5", "fclk_div4", "fclk_div3" },
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_axg_ao_data = {
|
||||
.parent_names = pwm_axg_ao_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names),
|
||||
};
|
||||
|
||||
static const char * const pwm_g12a_ao_ab_parent_names[] = {
|
||||
"xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5"
|
||||
.parent_names = { "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" },
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
|
||||
.parent_names = pwm_g12a_ao_ab_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_names),
|
||||
};
|
||||
|
||||
static const char * const pwm_g12a_ao_cd_parent_names[] = {
|
||||
"xtal", "g12a_ao_clk81",
|
||||
.parent_names = { "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" },
|
||||
};
|
||||
|
||||
static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
|
||||
.parent_names = pwm_g12a_ao_cd_parent_names,
|
||||
.num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names),
|
||||
.parent_names = { "xtal", "g12a_ao_clk81", NULL, NULL },
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_pwm_matches[] = {
|
||||
@ -432,20 +403,21 @@ static const struct of_device_id meson_pwm_matches[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
|
||||
|
||||
static int meson_pwm_init_channels(struct meson_pwm *meson)
|
||||
static int meson_pwm_init_channels(struct pwm_chip *chip)
|
||||
{
|
||||
struct clk_parent_data mux_parent_data[MESON_MAX_MUX_PARENTS] = {};
|
||||
struct device *dev = meson->chip.dev;
|
||||
struct meson_pwm *meson = to_meson_pwm(chip);
|
||||
struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {};
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
unsigned int i;
|
||||
char name[255];
|
||||
int err;
|
||||
|
||||
for (i = 0; i < meson->data->num_parents; i++) {
|
||||
for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) {
|
||||
mux_parent_data[i].index = -1;
|
||||
mux_parent_data[i].name = meson->data->parent_names[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < meson->chip.npwm; i++) {
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct meson_pwm_channel *channel = &meson->channels[i];
|
||||
struct clk_parent_data div_parent = {}, gate_parent = {};
|
||||
struct clk_init_data init = {};
|
||||
@ -456,7 +428,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
|
||||
init.ops = &clk_mux_ops;
|
||||
init.flags = 0;
|
||||
init.parent_data = mux_parent_data;
|
||||
init.num_parents = meson->data->num_parents;
|
||||
init.num_parents = MESON_NUM_MUX_PARENTS;
|
||||
|
||||
channel->mux.reg = meson->base + REG_MISC_AB;
|
||||
channel->mux.shift =
|
||||
@ -525,29 +497,29 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
|
||||
|
||||
static int meson_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct meson_pwm *meson;
|
||||
int err;
|
||||
|
||||
meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL);
|
||||
if (!meson)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, MESON_NUM_PWMS, sizeof(*meson));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
meson = to_meson_pwm(chip);
|
||||
|
||||
meson->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(meson->base))
|
||||
return PTR_ERR(meson->base);
|
||||
|
||||
spin_lock_init(&meson->lock);
|
||||
meson->chip.dev = &pdev->dev;
|
||||
meson->chip.ops = &meson_pwm_ops;
|
||||
meson->chip.npwm = MESON_NUM_PWMS;
|
||||
chip->ops = &meson_pwm_ops;
|
||||
|
||||
meson->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
err = meson_pwm_init_channels(meson);
|
||||
err = meson_pwm_init_channels(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = devm_pwmchip_add(&pdev->dev, &meson->chip);
|
||||
err = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (err < 0)
|
||||
return dev_err_probe(&pdev->dev, err,
|
||||
"failed to register PWM chip\n");
|
||||
|
@ -54,7 +54,6 @@
|
||||
#define MCHPCOREPWM_TIMEOUT_MS 100u
|
||||
|
||||
struct mchp_core_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct mutex lock; /* protects the shared period */
|
||||
@ -65,7 +64,7 @@ struct mchp_core_pwm_chip {
|
||||
|
||||
static inline struct mchp_core_pwm_chip *to_mchp_core_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct mchp_core_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void mchp_core_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -447,13 +446,15 @@ MODULE_DEVICE_TABLE(of, mchp_core_of_match);
|
||||
|
||||
static int mchp_core_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct mchp_core_pwm_chip *mchp_core_pwm;
|
||||
struct resource *regs;
|
||||
int ret;
|
||||
|
||||
mchp_core_pwm = devm_kzalloc(&pdev->dev, sizeof(*mchp_core_pwm), GFP_KERNEL);
|
||||
if (!mchp_core_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 16, sizeof(*mchp_core_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
mchp_core_pwm = to_mchp_core_pwm(chip);
|
||||
|
||||
mchp_core_pwm->base = devm_platform_get_and_ioremap_resource(pdev, 0, ®s);
|
||||
if (IS_ERR(mchp_core_pwm->base))
|
||||
@ -470,9 +471,7 @@ static int mchp_core_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&mchp_core_pwm->lock);
|
||||
|
||||
mchp_core_pwm->chip.dev = &pdev->dev;
|
||||
mchp_core_pwm->chip.ops = &mchp_core_pwm_ops;
|
||||
mchp_core_pwm->chip.npwm = 16;
|
||||
chip->ops = &mchp_core_pwm_ops;
|
||||
|
||||
mchp_core_pwm->channel_enabled = readb_relaxed(mchp_core_pwm->base + MCHPCOREPWM_EN(0));
|
||||
mchp_core_pwm->channel_enabled |=
|
||||
@ -485,7 +484,7 @@ static int mchp_core_pwm_probe(struct platform_device *pdev)
|
||||
writel_relaxed(1U, mchp_core_pwm->base + MCHPCOREPWM_SYNC_UPD);
|
||||
mchp_core_pwm->update_timestamp = ktime_get();
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &mchp_core_pwm->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to add pwmchip\n");
|
||||
|
||||
|
@ -42,7 +42,6 @@ struct mtk_pwm_data {
|
||||
};
|
||||
|
||||
struct mtk_disp_pwm {
|
||||
struct pwm_chip chip;
|
||||
const struct mtk_pwm_data *data;
|
||||
struct clk *clk_main;
|
||||
struct clk *clk_mm;
|
||||
@ -52,7 +51,7 @@ struct mtk_disp_pwm {
|
||||
|
||||
static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct mtk_disp_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
|
||||
@ -91,14 +90,14 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (!mdp->enabled) {
|
||||
err = clk_prepare_enable(mdp->clk_main);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n",
|
||||
dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n",
|
||||
ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_mm);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n",
|
||||
dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n",
|
||||
ERR_PTR(err));
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
return err;
|
||||
@ -181,13 +180,13 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_main);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
|
||||
dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_mm);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
|
||||
dev_err(pwmchip_parent(chip), "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
return err;
|
||||
}
|
||||
@ -231,12 +230,14 @@ static const struct pwm_ops mtk_disp_pwm_ops = {
|
||||
|
||||
static int mtk_disp_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct mtk_disp_pwm *mdp;
|
||||
int ret;
|
||||
|
||||
mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL);
|
||||
if (!mdp)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*mdp));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
mdp = to_mtk_disp_pwm(chip);
|
||||
|
||||
mdp->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
@ -254,11 +255,9 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_mm),
|
||||
"Failed to get mm clock\n");
|
||||
|
||||
mdp->chip.dev = &pdev->dev;
|
||||
mdp->chip.ops = &mtk_disp_pwm_ops;
|
||||
mdp->chip.npwm = 1;
|
||||
chip->ops = &mtk_disp_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &mdp->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
|
||||
|
@ -37,12 +37,14 @@ static const u8 cdiv_shift[PERIOD_CDIV_MAX] = {
|
||||
};
|
||||
|
||||
struct mxs_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip)
|
||||
static inline struct mxs_pwm_chip *to_mxs_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
@ -120,12 +122,21 @@ static const struct pwm_ops mxs_pwm_ops = {
|
||||
static int mxs_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct pwm_chip *chip;
|
||||
struct mxs_pwm_chip *mxs;
|
||||
u32 npwm;
|
||||
int ret;
|
||||
|
||||
mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL);
|
||||
if (!mxs)
|
||||
return -ENOMEM;
|
||||
ret = of_property_read_u32(np, "fsl,pwm-number", &npwm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*mxs));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
mxs = to_mxs_pwm_chip(chip);
|
||||
|
||||
mxs->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mxs->base))
|
||||
@ -135,21 +146,14 @@ static int mxs_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(mxs->clk))
|
||||
return PTR_ERR(mxs->clk);
|
||||
|
||||
mxs->chip.dev = &pdev->dev;
|
||||
mxs->chip.ops = &mxs_pwm_ops;
|
||||
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
chip->ops = &mxs_pwm_ops;
|
||||
|
||||
/* FIXME: Only do this if the PWM isn't already running */
|
||||
ret = stmp_reset_block(mxs->base);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to reset PWM\n");
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &mxs->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret);
|
||||
return ret;
|
||||
|
@ -25,12 +25,11 @@
|
||||
|
||||
struct ntxec_pwm {
|
||||
struct ntxec *ec;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ntxec_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
#define NTXEC_REG_AUTO_OFF_HI 0xa1
|
||||
@ -141,16 +140,13 @@ static int ntxec_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = ntxec_pwm_from_chip(chip);
|
||||
|
||||
priv->ec = ec;
|
||||
|
||||
chip = &priv->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->ops = &ntxec_pwm_ops;
|
||||
chip->npwm = 1;
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
@ -53,13 +53,11 @@
|
||||
/**
|
||||
* struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
|
||||
* corresponding to omap dmtimer.
|
||||
* @chip: PWM chip structure representing PWM controller
|
||||
* @dm_timer: Pointer to omap dm timer.
|
||||
* @pdata: Pointer to omap dm timer ops.
|
||||
* @dm_timer_pdev: Pointer to omap dm timer platform device
|
||||
*/
|
||||
struct pwm_omap_dmtimer_chip {
|
||||
struct pwm_chip chip;
|
||||
/* Mutex to protect pwm apply state */
|
||||
struct omap_dm_timer *dm_timer;
|
||||
const struct omap_dm_timer_ops *pdata;
|
||||
@ -69,7 +67,7 @@ struct pwm_omap_dmtimer_chip {
|
||||
static inline struct pwm_omap_dmtimer_chip *
|
||||
to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +153,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
|
||||
unsigned long clk_rate;
|
||||
struct clk *fclk;
|
||||
|
||||
dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
|
||||
dev_dbg(pwmchip_parent(chip), "requested duty cycle: %d ns, period: %d ns\n",
|
||||
duty_ns, period_ns);
|
||||
|
||||
if (duty_ns == pwm_get_duty_cycle(pwm) &&
|
||||
@ -164,17 +162,17 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
|
||||
|
||||
fclk = omap->pdata->get_fclk(omap->dm_timer);
|
||||
if (!fclk) {
|
||||
dev_err(chip->dev, "invalid pmtimer fclk\n");
|
||||
dev_err(pwmchip_parent(chip), "invalid pmtimer fclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_rate = clk_get_rate(fclk);
|
||||
if (!clk_rate) {
|
||||
dev_err(chip->dev, "invalid pmtimer fclk rate\n");
|
||||
dev_err(pwmchip_parent(chip), "invalid pmtimer fclk rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
|
||||
dev_dbg(pwmchip_parent(chip), "clk rate: %luHz\n", clk_rate);
|
||||
|
||||
/*
|
||||
* Calculate the appropriate load and match values based on the
|
||||
@ -196,27 +194,27 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
|
||||
duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
|
||||
|
||||
if (period_cycles < 2) {
|
||||
dev_info(chip->dev,
|
||||
dev_info(pwmchip_parent(chip),
|
||||
"period %d ns too short for clock rate %lu Hz\n",
|
||||
period_ns, clk_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (duty_cycles < 1) {
|
||||
dev_dbg(chip->dev,
|
||||
dev_dbg(pwmchip_parent(chip),
|
||||
"duty cycle %d ns is too short for clock rate %lu Hz\n",
|
||||
duty_ns, clk_rate);
|
||||
dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
|
||||
dev_dbg(pwmchip_parent(chip), "using minimum of 1 clock cycle\n");
|
||||
duty_cycles = 1;
|
||||
} else if (duty_cycles >= period_cycles) {
|
||||
dev_dbg(chip->dev,
|
||||
dev_dbg(pwmchip_parent(chip),
|
||||
"duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
|
||||
duty_ns, period_ns, clk_rate);
|
||||
dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
|
||||
dev_dbg(pwmchip_parent(chip), "using maximum of 1 clock cycle less than period\n");
|
||||
duty_cycles = period_cycles - 1;
|
||||
}
|
||||
|
||||
dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n",
|
||||
dev_dbg(pwmchip_parent(chip), "effective duty cycle: %lld ns, period: %lld ns\n",
|
||||
DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles,
|
||||
clk_rate),
|
||||
DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles,
|
||||
@ -228,7 +226,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
|
||||
omap->pdata->set_load(omap->dm_timer, load_value);
|
||||
omap->pdata->set_match(omap->dm_timer, true, match_value);
|
||||
|
||||
dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
|
||||
dev_dbg(pwmchip_parent(chip), "load value: %#08x (%d), match value: %#08x (%d)\n",
|
||||
load_value, load_value, match_value, match_value);
|
||||
|
||||
return 0;
|
||||
@ -311,6 +309,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
struct dmtimer_platform_data *timer_pdata;
|
||||
const struct omap_dm_timer_ops *pdata;
|
||||
struct platform_device *timer_pdev;
|
||||
struct pwm_chip *chip;
|
||||
struct pwm_omap_dmtimer_chip *omap;
|
||||
struct omap_dm_timer *dm_timer;
|
||||
struct device_node *timer;
|
||||
@ -368,11 +367,12 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
goto err_request_timer;
|
||||
}
|
||||
|
||||
omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
|
||||
if (!omap) {
|
||||
ret = -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*omap));
|
||||
if (IS_ERR(chip)) {
|
||||
ret = PTR_ERR(chip);
|
||||
goto err_alloc_omap;
|
||||
}
|
||||
omap = to_pwm_omap_dmtimer_chip(chip);
|
||||
|
||||
omap->pdata = pdata;
|
||||
omap->dm_timer = dm_timer;
|
||||
@ -392,11 +392,9 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
|
||||
omap->pdata->set_source(omap->dm_timer, v);
|
||||
|
||||
omap->chip.dev = &pdev->dev;
|
||||
omap->chip.ops = &pwm_omap_dmtimer_ops;
|
||||
omap->chip.npwm = 1;
|
||||
chip->ops = &pwm_omap_dmtimer_ops;
|
||||
|
||||
ret = pwmchip_add(&omap->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register PWM\n");
|
||||
goto err_pwmchip_add;
|
||||
@ -404,7 +402,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
|
||||
of_node_put(timer);
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -432,9 +430,10 @@ err_find_timer_pdev:
|
||||
|
||||
static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
|
||||
|
||||
pwmchip_remove(&omap->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
if (pm_runtime_active(&omap->dm_timer_pdev->dev))
|
||||
omap->pdata->stop(omap->dm_timer);
|
||||
|
@ -76,7 +76,6 @@
|
||||
#define REG_OFF_L(C) ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : LED_N_OFF_L((C)))
|
||||
|
||||
struct pca9685 {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
struct mutex lock;
|
||||
DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
|
||||
@ -88,7 +87,7 @@ struct pca9685 {
|
||||
|
||||
static inline struct pca9685 *to_pca(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pca9685, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/* This function is supposed to be called with the lock mutex held */
|
||||
@ -107,9 +106,10 @@ static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel)
|
||||
return test_bit(channel, pca->pwms_enabled);
|
||||
}
|
||||
|
||||
static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned int *val)
|
||||
static int pca9685_read_reg(struct pwm_chip *chip, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct device *dev = pca->chip.dev;
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
int err;
|
||||
|
||||
err = regmap_read(pca->regmap, reg, val);
|
||||
@ -119,9 +119,10 @@ static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned int
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int val)
|
||||
static int pca9685_write_reg(struct pwm_chip *chip, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct device *dev = pca->chip.dev;
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
int err;
|
||||
|
||||
err = regmap_write(pca->regmap, reg, val);
|
||||
@ -132,19 +133,19 @@ static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int
|
||||
}
|
||||
|
||||
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
|
||||
static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int duty)
|
||||
static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsigned int duty)
|
||||
{
|
||||
struct pwm_device *pwm = &pca->chip.pwms[channel];
|
||||
struct pwm_device *pwm = &chip->pwms[channel];
|
||||
unsigned int on, off;
|
||||
|
||||
if (duty == 0) {
|
||||
/* Set the full OFF bit, which has the highest precedence */
|
||||
pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
|
||||
pca9685_write_reg(chip, REG_OFF_H(channel), LED_FULL);
|
||||
return;
|
||||
} else if (duty >= PCA9685_COUNTER_RANGE) {
|
||||
/* Set the full ON bit and clear the full OFF bit */
|
||||
pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
|
||||
pca9685_write_reg(pca, REG_OFF_H(channel), 0);
|
||||
pca9685_write_reg(chip, REG_ON_H(channel), LED_FULL);
|
||||
pca9685_write_reg(chip, REG_OFF_H(channel), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -164,16 +165,16 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int
|
||||
off = (on + duty) % PCA9685_COUNTER_RANGE;
|
||||
|
||||
/* Set ON time (clears full ON bit) */
|
||||
pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
|
||||
pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
|
||||
pca9685_write_reg(chip, REG_ON_L(channel), on & 0xff);
|
||||
pca9685_write_reg(chip, REG_ON_H(channel), (on >> 8) & 0xf);
|
||||
/* Set OFF time (clears full OFF bit) */
|
||||
pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
|
||||
pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
|
||||
pca9685_write_reg(chip, REG_OFF_L(channel), off & 0xff);
|
||||
pca9685_write_reg(chip, REG_OFF_H(channel), (off >> 8) & 0xf);
|
||||
}
|
||||
|
||||
static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
|
||||
static unsigned int pca9685_pwm_get_duty(struct pwm_chip *chip, int channel)
|
||||
{
|
||||
struct pwm_device *pwm = &pca->chip.pwms[channel];
|
||||
struct pwm_device *pwm = &chip->pwms[channel];
|
||||
unsigned int off = 0, on = 0, val = 0;
|
||||
|
||||
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
|
||||
@ -181,25 +182,25 @@ static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pca9685_read_reg(pca, LED_N_OFF_H(channel), &off);
|
||||
pca9685_read_reg(chip, LED_N_OFF_H(channel), &off);
|
||||
if (off & LED_FULL) {
|
||||
/* Full OFF bit is set */
|
||||
return 0;
|
||||
}
|
||||
|
||||
pca9685_read_reg(pca, LED_N_ON_H(channel), &on);
|
||||
pca9685_read_reg(chip, LED_N_ON_H(channel), &on);
|
||||
if (on & LED_FULL) {
|
||||
/* Full ON bit is set */
|
||||
return PCA9685_COUNTER_RANGE;
|
||||
}
|
||||
|
||||
pca9685_read_reg(pca, LED_N_OFF_L(channel), &val);
|
||||
pca9685_read_reg(chip, LED_N_OFF_L(channel), &val);
|
||||
off = ((off & 0xf) << 8) | (val & 0xff);
|
||||
if (!pwm->state.usage_power)
|
||||
return off;
|
||||
|
||||
/* Read ON register to calculate duty cycle of staggered output */
|
||||
if (pca9685_read_reg(pca, LED_N_ON_L(channel), &val)) {
|
||||
if (pca9685_read_reg(chip, LED_N_ON_L(channel), &val)) {
|
||||
/* Reset val to 0 in case reading LED_N_ON_L failed */
|
||||
val = 0;
|
||||
}
|
||||
@ -247,35 +248,37 @@ static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
|
||||
|
||||
static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_chip *chip = gpiochip_get_data(gpio);
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
|
||||
if (pca9685_pwm_test_and_set_inuse(pca, offset))
|
||||
return -EBUSY;
|
||||
pm_runtime_get_sync(pca->chip.dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_chip *chip = gpiochip_get_data(gpio);
|
||||
|
||||
return pca9685_pwm_get_duty(pca, offset) != 0;
|
||||
return pca9685_pwm_get_duty(chip, offset) != 0;
|
||||
}
|
||||
|
||||
static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_chip *chip = gpiochip_get_data(gpio);
|
||||
|
||||
pca9685_pwm_set_duty(pca, offset, value ? PCA9685_COUNTER_RANGE : 0);
|
||||
pca9685_pwm_set_duty(chip, offset, value ? PCA9685_COUNTER_RANGE : 0);
|
||||
}
|
||||
|
||||
static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_chip *chip = gpiochip_get_data(gpio);
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
|
||||
pca9685_pwm_set_duty(pca, offset, 0);
|
||||
pm_runtime_put(pca->chip.dev);
|
||||
pca9685_pwm_set_duty(chip, offset, 0);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
pca9685_pwm_clear_inuse(pca, offset);
|
||||
}
|
||||
|
||||
@ -306,9 +309,10 @@ static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
|
||||
* expose a GPIO chip here which can exclusively take over the underlying
|
||||
* PWM channel.
|
||||
*/
|
||||
static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||
static int pca9685_pwm_gpio_probe(struct pwm_chip *chip)
|
||||
{
|
||||
struct device *dev = pca->chip.dev;
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
|
||||
pca->gpio.label = dev_name(dev);
|
||||
pca->gpio.parent = dev;
|
||||
@ -323,7 +327,7 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||
pca->gpio.ngpio = PCA9685_MAXCHAN;
|
||||
pca->gpio.can_sleep = true;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &pca->gpio, pca);
|
||||
return devm_gpiochip_add_data(dev, &pca->gpio, chip);
|
||||
}
|
||||
#else
|
||||
static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca,
|
||||
@ -337,15 +341,16 @@ pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||
static inline int pca9685_pwm_gpio_probe(struct pwm_chip *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
|
||||
static void pca9685_set_sleep_mode(struct pwm_chip *chip, bool enable)
|
||||
{
|
||||
struct device *dev = pca->chip.dev;
|
||||
struct device *dev = pwmchip_parent(chip);
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
int err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
|
||||
MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
|
||||
if (err) {
|
||||
@ -373,19 +378,19 @@ static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
prescale = DIV_ROUND_CLOSEST_ULL(PCA9685_OSC_CLOCK_MHZ * state->period,
|
||||
PCA9685_COUNTER_RANGE * 1000) - 1;
|
||||
if (prescale < PCA9685_PRESCALE_MIN || prescale > PCA9685_PRESCALE_MAX) {
|
||||
dev_err(chip->dev, "pwm not changed: period out of bounds!\n");
|
||||
dev_err(pwmchip_parent(chip), "pwm not changed: period out of bounds!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||
pca9685_pwm_set_duty(chip, pwm->hwpwm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
|
||||
pca9685_read_reg(chip, PCA9685_PRESCALE, &val);
|
||||
if (prescale != val) {
|
||||
if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"pwm not changed: periods of enabled pwms must match!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -397,18 +402,18 @@ static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* state is guaranteed active here.
|
||||
*/
|
||||
/* Put chip into sleep mode */
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
pca9685_set_sleep_mode(chip, true);
|
||||
|
||||
/* Change the chip-wide output frequency */
|
||||
pca9685_write_reg(pca, PCA9685_PRESCALE, prescale);
|
||||
pca9685_write_reg(chip, PCA9685_PRESCALE, prescale);
|
||||
|
||||
/* Wake the chip up */
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
pca9685_set_sleep_mode(chip, false);
|
||||
}
|
||||
|
||||
duty = PCA9685_COUNTER_RANGE * state->duty_cycle;
|
||||
duty = DIV_ROUND_UP_ULL(duty, state->period);
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, duty);
|
||||
pca9685_pwm_set_duty(chip, pwm->hwpwm, duty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -434,12 +439,11 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static int pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned long long duty;
|
||||
unsigned int val = 0;
|
||||
|
||||
/* Calculate (chip-wide) period from prescale value */
|
||||
pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
|
||||
pca9685_read_reg(chip, PCA9685_PRESCALE, &val);
|
||||
/*
|
||||
* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
|
||||
* The following calculation is therefore only a multiplication
|
||||
@ -462,7 +466,7 @@ static int pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
state->enabled = true;
|
||||
duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
|
||||
duty = pca9685_pwm_get_duty(chip, pwm->hwpwm);
|
||||
state->duty_cycle = DIV_ROUND_DOWN_ULL(duty * state->period, PCA9685_COUNTER_RANGE);
|
||||
|
||||
return 0;
|
||||
@ -482,7 +486,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_unlock(&pca->lock);
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -492,11 +496,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
|
||||
mutex_lock(&pca->lock);
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||
pca9685_pwm_set_duty(chip, pwm->hwpwm, 0);
|
||||
clear_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||
mutex_unlock(&pca->lock);
|
||||
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
|
||||
}
|
||||
|
||||
@ -516,13 +520,16 @@ static const struct regmap_config pca9685_regmap_i2c_config = {
|
||||
|
||||
static int pca9685_pwm_probe(struct i2c_client *client)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct pca9685 *pca;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL);
|
||||
if (!pca)
|
||||
return -ENOMEM;
|
||||
/* Add an extra channel for ALL_LED */
|
||||
chip = devm_pwmchip_alloc(&client->dev, PCA9685_MAXCHAN + 1, sizeof(*pca));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pca = to_pca(chip);
|
||||
|
||||
pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config);
|
||||
if (IS_ERR(pca->regmap)) {
|
||||
@ -532,11 +539,11 @@ static int pca9685_pwm_probe(struct i2c_client *client)
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, pca);
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
mutex_init(&pca->lock);
|
||||
|
||||
ret = pca9685_read_reg(pca, PCA9685_MODE2, ®);
|
||||
ret = pca9685_read_reg(chip, PCA9685_MODE2, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -550,34 +557,30 @@ static int pca9685_pwm_probe(struct i2c_client *client)
|
||||
else
|
||||
reg |= MODE2_OUTDRV;
|
||||
|
||||
ret = pca9685_write_reg(pca, PCA9685_MODE2, reg);
|
||||
ret = pca9685_write_reg(chip, PCA9685_MODE2, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
|
||||
pca9685_read_reg(pca, PCA9685_MODE1, ®);
|
||||
pca9685_read_reg(chip, PCA9685_MODE1, ®);
|
||||
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
|
||||
pca9685_write_reg(pca, PCA9685_MODE1, reg);
|
||||
pca9685_write_reg(chip, PCA9685_MODE1, reg);
|
||||
|
||||
/* Reset OFF/ON registers to POR default */
|
||||
pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, 0);
|
||||
pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_H, LED_FULL);
|
||||
pca9685_write_reg(pca, PCA9685_ALL_LED_ON_L, 0);
|
||||
pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, LED_FULL);
|
||||
pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_L, 0);
|
||||
pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_H, LED_FULL);
|
||||
pca9685_write_reg(chip, PCA9685_ALL_LED_ON_L, 0);
|
||||
pca9685_write_reg(chip, PCA9685_ALL_LED_ON_H, LED_FULL);
|
||||
|
||||
pca->chip.ops = &pca9685_pwm_ops;
|
||||
/* Add an extra channel for ALL_LED */
|
||||
pca->chip.npwm = PCA9685_MAXCHAN + 1;
|
||||
chip->ops = &pca9685_pwm_ops;
|
||||
|
||||
pca->chip.dev = &client->dev;
|
||||
|
||||
ret = pwmchip_add(&pca->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pca9685_pwm_gpio_probe(pca);
|
||||
ret = pca9685_pwm_gpio_probe(chip);
|
||||
if (ret < 0) {
|
||||
pwmchip_remove(&pca->chip);
|
||||
pwmchip_remove(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -588,11 +591,11 @@ static int pca9685_pwm_probe(struct i2c_client *client)
|
||||
* Although the chip comes out of power-up in the sleep state,
|
||||
* we force it to sleep in case it was woken up before
|
||||
*/
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
pca9685_set_sleep_mode(chip, true);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
} else {
|
||||
/* Wake the chip up if runtime PM is disabled */
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
pca9685_set_sleep_mode(chip, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -600,13 +603,13 @@ static int pca9685_pwm_probe(struct i2c_client *client)
|
||||
|
||||
static void pca9685_pwm_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pca9685 *pca = i2c_get_clientdata(client);
|
||||
struct pwm_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
pwmchip_remove(&pca->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
if (!pm_runtime_enabled(&client->dev)) {
|
||||
/* Put chip in sleep state if runtime PM is disabled */
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
pca9685_set_sleep_mode(chip, true);
|
||||
}
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
@ -615,18 +618,18 @@ static void pca9685_pwm_remove(struct i2c_client *client)
|
||||
static int __maybe_unused pca9685_pwm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pca9685 *pca = i2c_get_clientdata(client);
|
||||
struct pwm_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
pca9685_set_sleep_mode(chip, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused pca9685_pwm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pca9685 *pca = i2c_get_clientdata(client);
|
||||
struct pwm_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
pca9685_set_sleep_mode(chip, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(platform, pwm_id_table);
|
||||
#define PWMDCR_FD (1 << 10)
|
||||
|
||||
struct pxa_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct device *dev;
|
||||
|
||||
struct clk *clk;
|
||||
@ -58,7 +57,7 @@ struct pxa_pwm_chip {
|
||||
|
||||
static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pxa_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -159,6 +158,7 @@ MODULE_DEVICE_TABLE(of, pwm_of_match);
|
||||
static int pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct pwm_chip *chip;
|
||||
struct pxa_pwm_chip *pc;
|
||||
int ret = 0;
|
||||
|
||||
@ -168,28 +168,27 @@ static int pwm_probe(struct platform_device *pdev)
|
||||
if (id == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (pc == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev,
|
||||
(id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1,
|
||||
sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_pxa_pwm_chip(chip);
|
||||
|
||||
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pc->clk))
|
||||
return PTR_ERR(pc->clk);
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &pxa_pwm_ops;
|
||||
pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
||||
chip->ops = &pxa_pwm_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF)) {
|
||||
pc->chip.of_xlate = of_pwm_single_xlate;
|
||||
pc->chip.of_pwm_n_cells = 1;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
chip->of_xlate = of_pwm_single_xlate;
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
return PTR_ERR(pc->mmio_base);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
struct raspberrypi_pwm {
|
||||
struct rpi_firmware *firmware;
|
||||
struct pwm_chip chip;
|
||||
unsigned int duty_cycle;
|
||||
};
|
||||
|
||||
@ -40,7 +39,7 @@ struct raspberrypi_pwm_prop {
|
||||
static inline
|
||||
struct raspberrypi_pwm *raspberrypi_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct raspberrypi_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware,
|
||||
@ -122,7 +121,7 @@ static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
|
||||
duty_cycle);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to set duty cycle: %pe\n",
|
||||
dev_err(pwmchip_parent(chip), "Failed to set duty cycle: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
@ -142,6 +141,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
|
||||
struct device_node *firmware_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rpi_firmware *firmware;
|
||||
struct pwm_chip *chip;
|
||||
struct raspberrypi_pwm *rpipwm;
|
||||
int ret;
|
||||
|
||||
@ -157,14 +157,14 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(dev, -EPROBE_DEFER,
|
||||
"Failed to get firmware handle\n");
|
||||
|
||||
rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL);
|
||||
if (!rpipwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, RASPBERRYPI_FIRMWARE_PWM_NUM,
|
||||
sizeof(*rpipwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
rpipwm = raspberrypi_pwm_from_chip(chip);
|
||||
|
||||
rpipwm->firmware = firmware;
|
||||
rpipwm->chip.dev = dev;
|
||||
rpipwm->chip.ops = &raspberrypi_pwm_ops;
|
||||
rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM;
|
||||
chip->ops = &raspberrypi_pwm_ops;
|
||||
|
||||
ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
|
||||
&rpipwm->duty_cycle);
|
||||
@ -173,7 +173,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_pwmchip_add(dev, &rpipwm->chip);
|
||||
return devm_pwmchip_add(dev, chip);
|
||||
}
|
||||
|
||||
static const struct of_device_id raspberrypi_pwm_of_match[] = {
|
||||
|
@ -38,14 +38,13 @@
|
||||
#define RCAR_PWMCNT_PH0_SHIFT 0
|
||||
|
||||
struct rcar_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct rcar_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data,
|
||||
@ -132,12 +131,12 @@ static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
|
||||
|
||||
static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
return pm_runtime_get_sync(chip->dev);
|
||||
return pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int rcar_pwm_enable(struct rcar_pwm_chip *rp)
|
||||
@ -202,12 +201,14 @@ static const struct pwm_ops rcar_pwm_ops = {
|
||||
|
||||
static int rcar_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rcar_pwm_chip *rcar_pwm;
|
||||
int ret;
|
||||
|
||||
rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL);
|
||||
if (rcar_pwm == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*rcar_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
rcar_pwm = to_rcar_pwm_chip(chip);
|
||||
|
||||
rcar_pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(rcar_pwm->base))
|
||||
@ -219,15 +220,13 @@ static int rcar_pwm_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(rcar_pwm->clk);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rcar_pwm);
|
||||
chip->ops = &rcar_pwm_ops;
|
||||
|
||||
rcar_pwm->chip.dev = &pdev->dev;
|
||||
rcar_pwm->chip.ops = &rcar_pwm_ops;
|
||||
rcar_pwm->chip.npwm = 1;
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = pwmchip_add(&rcar_pwm->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
@ -239,9 +238,9 @@ static int rcar_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
static void rcar_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&rcar_pwm->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
@ -79,7 +79,6 @@ struct tpu_pwm_device {
|
||||
|
||||
struct tpu_device {
|
||||
struct platform_device *pdev;
|
||||
struct pwm_chip chip;
|
||||
spinlock_t lock;
|
||||
|
||||
void __iomem *base;
|
||||
@ -87,7 +86,10 @@ struct tpu_device {
|
||||
struct tpu_pwm_device tpd[TPU_CHANNEL_MAX];
|
||||
};
|
||||
|
||||
#define to_tpu_device(c) container_of(c, struct tpu_device, chip)
|
||||
static inline struct tpu_device *to_tpu_device(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void tpu_pwm_write(struct tpu_pwm_device *tpd, int reg_nr, u16 value)
|
||||
{
|
||||
@ -438,12 +440,14 @@ static const struct pwm_ops tpu_pwm_ops = {
|
||||
|
||||
static int tpu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct tpu_device *tpu;
|
||||
int ret;
|
||||
|
||||
tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
|
||||
if (tpu == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, TPU_CHANNEL_MAX, sizeof(*tpu));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
tpu = to_tpu_device(chip);
|
||||
|
||||
spin_lock_init(&tpu->lock);
|
||||
tpu->pdev = pdev;
|
||||
@ -460,15 +464,13 @@ static int tpu_probe(struct platform_device *pdev)
|
||||
/* Initialize and register the device. */
|
||||
platform_set_drvdata(pdev, tpu);
|
||||
|
||||
tpu->chip.dev = &pdev->dev;
|
||||
tpu->chip.ops = &tpu_pwm_ops;
|
||||
tpu->chip.npwm = TPU_CHANNEL_MAX;
|
||||
chip->ops = &tpu_pwm_ops;
|
||||
|
||||
ret = devm_pm_runtime_enable(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to enable runtime PM\n");
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &tpu->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Failed to register PWM chip\n");
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
#define PWM_LP_DISABLE (0 << 8)
|
||||
|
||||
struct rockchip_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
struct clk *pclk;
|
||||
const struct rockchip_pwm_data *data;
|
||||
@ -54,7 +53,7 @@ struct rockchip_pwm_data {
|
||||
|
||||
static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct rockchip_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
@ -296,14 +295,16 @@ MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
|
||||
|
||||
static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
u32 enable_conf, ctrl;
|
||||
bool enabled;
|
||||
int ret, count;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
pc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->base))
|
||||
@ -337,18 +338,16 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
pc->data = device_get_match_data(&pdev->dev);
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &rockchip_pwm_ops;
|
||||
pc->chip.npwm = 1;
|
||||
chip->ops = &rockchip_pwm_ops;
|
||||
|
||||
enable_conf = pc->data->enable_conf;
|
||||
ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
|
||||
enabled = (ctrl & enable_conf) == enable_conf;
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
goto err_pclk;
|
||||
@ -372,9 +371,10 @@ err_clk:
|
||||
|
||||
static void rockchip_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_unprepare(pc->pclk);
|
||||
clk_unprepare(pc->clk);
|
||||
|
@ -61,7 +61,6 @@ struct rz_mtu3_pwm_channel {
|
||||
/**
|
||||
* struct rz_mtu3_pwm_chip - MTU3 pwm private data
|
||||
*
|
||||
* @chip: MTU3 pwm chip data
|
||||
* @clk: MTU3 module clock
|
||||
* @lock: Lock to prevent concurrent access for usage count
|
||||
* @rate: MTU3 clock rate
|
||||
@ -72,7 +71,6 @@ struct rz_mtu3_pwm_channel {
|
||||
*/
|
||||
|
||||
struct rz_mtu3_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
struct mutex lock;
|
||||
unsigned long rate;
|
||||
@ -92,7 +90,7 @@ static const struct rz_mtu3_channel_io_map channel_map[] = {
|
||||
|
||||
static inline struct rz_mtu3_pwm_chip *to_rz_mtu3_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct rz_mtu3_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static void rz_mtu3_pwm_read_tgr_registers(struct rz_mtu3_pwm_channel *priv,
|
||||
@ -211,15 +209,15 @@ static void rz_mtu3_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_unlock(&rz_mtu3_pwm->lock);
|
||||
}
|
||||
|
||||
static int rz_mtu3_pwm_enable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
|
||||
struct pwm_device *pwm)
|
||||
static int rz_mtu3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
struct rz_mtu3_pwm_channel *priv;
|
||||
u32 ch;
|
||||
u8 val;
|
||||
int rc;
|
||||
|
||||
rc = pm_runtime_resume_and_get(rz_mtu3_pwm->chip.dev);
|
||||
rc = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -243,9 +241,9 @@ static int rz_mtu3_pwm_enable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rz_mtu3_pwm_disable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
|
||||
struct pwm_device *pwm)
|
||||
static void rz_mtu3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
struct rz_mtu3_pwm_channel *priv;
|
||||
u32 ch;
|
||||
|
||||
@ -265,7 +263,7 @@ static void rz_mtu3_pwm_disable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
|
||||
|
||||
mutex_unlock(&rz_mtu3_pwm->lock);
|
||||
|
||||
pm_runtime_put_sync(rz_mtu3_pwm->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -274,7 +272,7 @@ static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
int rc;
|
||||
|
||||
rc = pm_runtime_resume_and_get(chip->dev);
|
||||
rc = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -307,7 +305,7 @@ static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -362,7 +360,7 @@ static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (!pwm->state.enabled) {
|
||||
int rc;
|
||||
|
||||
rc = pm_runtime_resume_and_get(chip->dev);
|
||||
rc = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@ -399,7 +397,7 @@ static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
/* If the PWM is not enabled, turn the clock off again to save power. */
|
||||
if (!pwm->state.enabled)
|
||||
pm_runtime_put(chip->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -416,7 +414,7 @@ static int rz_mtu3_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
if (!state->enabled) {
|
||||
if (enabled)
|
||||
rz_mtu3_pwm_disable(rz_mtu3_pwm, pwm);
|
||||
rz_mtu3_pwm_disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -428,7 +426,7 @@ static int rz_mtu3_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return ret;
|
||||
|
||||
if (!enabled)
|
||||
ret = rz_mtu3_pwm_enable(rz_mtu3_pwm, pwm);
|
||||
ret = rz_mtu3_pwm_enable(chip, pwm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -442,7 +440,8 @@ static const struct pwm_ops rz_mtu3_pwm_ops = {
|
||||
|
||||
static int rz_mtu3_pwm_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
|
||||
clk_disable_unprepare(rz_mtu3_pwm->clk);
|
||||
|
||||
@ -451,7 +450,8 @@ static int rz_mtu3_pwm_pm_runtime_suspend(struct device *dev)
|
||||
|
||||
static int rz_mtu3_pwm_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
|
||||
return clk_prepare_enable(rz_mtu3_pwm->clk);
|
||||
}
|
||||
@ -462,24 +462,28 @@ static DEFINE_RUNTIME_DEV_PM_OPS(rz_mtu3_pwm_pm_ops,
|
||||
|
||||
static void rz_mtu3_pwm_pm_disable(void *data)
|
||||
{
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = data;
|
||||
struct pwm_chip *chip = data;
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
|
||||
clk_rate_exclusive_put(rz_mtu3_pwm->clk);
|
||||
pm_runtime_disable(rz_mtu3_pwm->chip.dev);
|
||||
pm_runtime_set_suspended(rz_mtu3_pwm->chip.dev);
|
||||
pm_runtime_disable(pwmchip_parent(chip));
|
||||
pm_runtime_set_suspended(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int rz_mtu3_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rz_mtu3 *parent_ddata = dev_get_drvdata(pdev->dev.parent);
|
||||
struct rz_mtu3_pwm_chip *rz_mtu3_pwm;
|
||||
struct pwm_chip *chip;
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned int i, j = 0;
|
||||
int ret;
|
||||
|
||||
rz_mtu3_pwm = devm_kzalloc(&pdev->dev, sizeof(*rz_mtu3_pwm), GFP_KERNEL);
|
||||
if (!rz_mtu3_pwm)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, RZ_MTU3_MAX_PWM_CHANNELS,
|
||||
sizeof(*rz_mtu3_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
|
||||
|
||||
rz_mtu3_pwm->clk = parent_ddata->clk;
|
||||
|
||||
@ -494,7 +498,7 @@ static int rz_mtu3_pwm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
mutex_init(&rz_mtu3_pwm->lock);
|
||||
platform_set_drvdata(pdev, rz_mtu3_pwm);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
ret = clk_prepare_enable(rz_mtu3_pwm->clk);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Clock enable failed\n");
|
||||
@ -514,15 +518,13 @@ static int rz_mtu3_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
rz_mtu3_pwm->chip.dev = &pdev->dev;
|
||||
ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_pwm_pm_disable,
|
||||
rz_mtu3_pwm);
|
||||
chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rz_mtu3_pwm->chip.ops = &rz_mtu3_pwm_ops;
|
||||
rz_mtu3_pwm->chip.npwm = RZ_MTU3_MAX_PWM_CHANNELS;
|
||||
ret = devm_pwmchip_add(&pdev->dev, &rz_mtu3_pwm->chip);
|
||||
chip->ops = &rz_mtu3_pwm_ops;
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -69,7 +69,6 @@ struct samsung_pwm_channel {
|
||||
|
||||
/**
|
||||
* struct samsung_pwm_chip - private data of PWM chip
|
||||
* @chip: generic PWM chip
|
||||
* @variant: local copy of hardware variant data
|
||||
* @inverter_mask: inverter status for all channels - one bit per channel
|
||||
* @disabled_mask: disabled status for all channels - one bit per channel
|
||||
@ -80,7 +79,6 @@ struct samsung_pwm_channel {
|
||||
* @channel: per channel driver data
|
||||
*/
|
||||
struct samsung_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct samsung_pwm_variant variant;
|
||||
u8 inverter_mask;
|
||||
u8 disabled_mask;
|
||||
@ -110,7 +108,7 @@ static DEFINE_SPINLOCK(samsung_pwm_lock);
|
||||
static inline
|
||||
struct samsung_pwm_chip *to_samsung_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct samsung_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline unsigned int to_tcon_channel(unsigned int channel)
|
||||
@ -181,9 +179,10 @@ static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *our_chip,
|
||||
return rate / (reg + 1);
|
||||
}
|
||||
|
||||
static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip,
|
||||
static unsigned long pwm_samsung_calc_tin(struct pwm_chip *chip,
|
||||
unsigned int chan, unsigned long freq)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
struct samsung_pwm_variant *variant = &our_chip->variant;
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
@ -197,12 +196,12 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip,
|
||||
return rate;
|
||||
}
|
||||
|
||||
dev_warn(our_chip->chip.dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
"tclk of PWM %d is inoperational, using tdiv\n", chan);
|
||||
}
|
||||
|
||||
rate = pwm_samsung_get_tin_rate(our_chip, chan);
|
||||
dev_dbg(our_chip->chip.dev, "tin parent at %lu\n", rate);
|
||||
dev_dbg(pwmchip_parent(chip), "tin parent at %lu\n", rate);
|
||||
|
||||
/*
|
||||
* Compare minimum PWM frequency that can be achieved with possible
|
||||
@ -232,7 +231,7 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
|
||||
if (!(our_chip->variant.output_mask & BIT(pwm->hwpwm))) {
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
"tried to request PWM channel %d without output\n",
|
||||
pwm->hwpwm);
|
||||
return -EINVAL;
|
||||
@ -326,12 +325,12 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
period = NSEC_PER_SEC / period_ns;
|
||||
|
||||
dev_dbg(our_chip->chip.dev, "duty_ns=%d, period_ns=%d (%u)\n",
|
||||
dev_dbg(pwmchip_parent(chip), "duty_ns=%d, period_ns=%d (%u)\n",
|
||||
duty_ns, period_ns, period);
|
||||
|
||||
tin_rate = pwm_samsung_calc_tin(our_chip, pwm->hwpwm, period);
|
||||
tin_rate = pwm_samsung_calc_tin(chip, pwm->hwpwm, period);
|
||||
|
||||
dev_dbg(our_chip->chip.dev, "tin_rate=%lu\n", tin_rate);
|
||||
dev_dbg(pwmchip_parent(chip), "tin_rate=%lu\n", tin_rate);
|
||||
|
||||
tin_ns = NSEC_PER_SEC / tin_rate;
|
||||
tcnt = period_ns / tin_ns;
|
||||
@ -355,8 +354,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
/* -1UL will give 100% duty. */
|
||||
--tcmp;
|
||||
|
||||
dev_dbg(our_chip->chip.dev,
|
||||
"tin_ns=%u, tcmp=%u/%u\n", tin_ns, tcmp, tcnt);
|
||||
dev_dbg(pwmchip_parent(chip), "tin_ns=%u, tcmp=%u/%u\n", tin_ns, tcmp, tcnt);
|
||||
|
||||
/* Update PWM registers. */
|
||||
writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
|
||||
@ -368,7 +366,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* shortly afer this update (before it autoreloaded the new values).
|
||||
*/
|
||||
if (oldtcmp == (u32) -1) {
|
||||
dev_dbg(our_chip->chip.dev, "Forcing manual update");
|
||||
dev_dbg(pwmchip_parent(chip), "Forcing manual update");
|
||||
pwm_samsung_manual_update(our_chip, pwm);
|
||||
}
|
||||
|
||||
@ -507,9 +505,10 @@ static const struct of_device_id samsung_pwm_matches[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
|
||||
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
static int pwm_samsung_parse_dt(struct pwm_chip *chip)
|
||||
{
|
||||
struct device_node *np = our_chip->chip.dev->of_node;
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
struct device_node *np = pwmchip_parent(chip)->of_node;
|
||||
const struct of_device_id *match;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
@ -523,7 +522,7 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
|
||||
of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
|
||||
if (val >= SAMSUNG_PWM_NUM) {
|
||||
dev_err(our_chip->chip.dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"%s: invalid channel index in samsung,pwm-outputs property\n",
|
||||
__func__);
|
||||
continue;
|
||||
@ -534,7 +533,7 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
static int pwm_samsung_parse_dt(struct pwm_chip *chip)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -544,27 +543,26 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct samsung_pwm_chip *our_chip;
|
||||
struct pwm_chip *chip;
|
||||
unsigned int chan;
|
||||
int ret;
|
||||
|
||||
our_chip = devm_kzalloc(&pdev->dev, sizeof(*our_chip), GFP_KERNEL);
|
||||
if (our_chip == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, SAMSUNG_PWM_NUM, sizeof(*our_chip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
our_chip = to_samsung_pwm_chip(chip);
|
||||
|
||||
our_chip->chip.dev = &pdev->dev;
|
||||
our_chip->chip.ops = &pwm_samsung_ops;
|
||||
our_chip->chip.npwm = SAMSUNG_PWM_NUM;
|
||||
chip->ops = &pwm_samsung_ops;
|
||||
our_chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
|
||||
ret = pwm_samsung_parse_dt(our_chip);
|
||||
ret = pwm_samsung_parse_dt(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(&pdev->dev, "no platform data specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pdev->dev.platform_data)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"no platform data specified\n");
|
||||
|
||||
memcpy(&our_chip->variant, pdev->dev.platform_data,
|
||||
sizeof(our_chip->variant));
|
||||
@ -574,17 +572,10 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(our_chip->base))
|
||||
return PTR_ERR(our_chip->base);
|
||||
|
||||
our_chip->base_clk = devm_clk_get(&pdev->dev, "timers");
|
||||
if (IS_ERR(our_chip->base_clk)) {
|
||||
dev_err(dev, "failed to get timer base clk\n");
|
||||
return PTR_ERR(our_chip->base_clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(our_chip->base_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable base clock\n");
|
||||
return ret;
|
||||
}
|
||||
our_chip->base_clk = devm_clk_get_enabled(&pdev->dev, "timers");
|
||||
if (IS_ERR(our_chip->base_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(our_chip->base_clk),
|
||||
"failed to get timer base clk\n");
|
||||
|
||||
for (chan = 0; chan < SAMSUNG_PWM_NUM; ++chan)
|
||||
if (our_chip->variant.output_mask & BIT(chan))
|
||||
@ -594,14 +585,11 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
our_chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
|
||||
our_chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
|
||||
|
||||
platform_set_drvdata(pdev, our_chip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
ret = pwmchip_add(&our_chip->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register PWM chip\n");
|
||||
clk_disable_unprepare(our_chip->base_clk);
|
||||
return ret;
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed to register PWM chip\n");
|
||||
|
||||
dev_dbg(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
|
||||
clk_get_rate(our_chip->base_clk),
|
||||
@ -611,19 +599,10 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_samsung_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&our_chip->chip);
|
||||
|
||||
clk_disable_unprepare(our_chip->base_clk);
|
||||
}
|
||||
|
||||
static int pwm_samsung_resume(struct device *dev)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = &our_chip->chip;
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SAMSUNG_PWM_NUM; i++) {
|
||||
@ -662,7 +641,6 @@ static struct platform_driver pwm_samsung_driver = {
|
||||
.of_match_table = of_match_ptr(samsung_pwm_matches),
|
||||
},
|
||||
.probe = pwm_samsung_probe,
|
||||
.remove_new = pwm_samsung_remove,
|
||||
};
|
||||
module_platform_driver(pwm_samsung_driver);
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#define PWM_SIFIVE_DEFAULT_PERIOD 10000000
|
||||
|
||||
struct pwm_sifive_ddata {
|
||||
struct pwm_chip chip;
|
||||
struct device *parent;
|
||||
struct mutex lock; /* lock to protect user_count and approx_period */
|
||||
struct notifier_block notifier;
|
||||
struct clk *clk;
|
||||
@ -54,7 +54,7 @@ struct pwm_sifive_ddata {
|
||||
static inline
|
||||
struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct pwm_sifive_ddata, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -102,7 +102,7 @@ static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
|
||||
/* As scale <= 15 the shift operation cannot overflow. */
|
||||
num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale);
|
||||
ddata->real_period = div64_ul(num, rate);
|
||||
dev_dbg(ddata->chip.dev,
|
||||
dev_dbg(ddata->parent,
|
||||
"New real_period = %u ns\n", ddata->real_period);
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (!enabled) {
|
||||
ret = clk_enable(ddata->clk);
|
||||
if (ret) {
|
||||
dev_err(ddata->chip.dev, "Enable clk failed\n");
|
||||
dev_err(pwmchip_parent(chip), "Enable clk failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -230,15 +230,14 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||
u32 val;
|
||||
unsigned int enabled_pwms = 0, enabled_clks = 1;
|
||||
|
||||
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, 4, sizeof(*ddata));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
ddata = pwm_sifive_chip_to_ddata(chip);
|
||||
ddata->parent = dev;
|
||||
mutex_init(&ddata->lock);
|
||||
chip = &ddata->chip;
|
||||
chip->dev = dev;
|
||||
chip->ops = &pwm_sifive_ops;
|
||||
chip->npwm = 4;
|
||||
|
||||
ddata->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ddata->regs))
|
||||
@ -296,7 +295,7 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||
goto unregister_clk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
|
||||
|
||||
return 0;
|
||||
@ -314,15 +313,16 @@ disable_clk:
|
||||
|
||||
static void pwm_sifive_remove(struct platform_device *dev)
|
||||
{
|
||||
struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(dev);
|
||||
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
||||
struct pwm_device *pwm;
|
||||
int ch;
|
||||
|
||||
pwmchip_remove(&ddata->chip);
|
||||
pwmchip_remove(chip);
|
||||
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
||||
|
||||
for (ch = 0; ch < ddata->chip.npwm; ch++) {
|
||||
pwm = &ddata->chip.pwms[ch];
|
||||
for (ch = 0; ch < chip->npwm; ch++) {
|
||||
pwm = &chip->pwms[ch];
|
||||
if (pwm->state.enabled)
|
||||
clk_disable(ddata->clk);
|
||||
}
|
||||
|
@ -81,14 +81,13 @@
|
||||
regmap_write((priv)->regmap, (priv)->offset + (reg), (val))
|
||||
|
||||
struct sl28cpld_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
static inline struct sl28cpld_pwm *sl28cpld_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sl28cpld_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int sl28cpld_pwm_get_state(struct pwm_chip *chip,
|
||||
@ -213,9 +212,10 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = sl28cpld_pwm_from_chip(chip);
|
||||
|
||||
priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!priv->regmap) {
|
||||
@ -231,10 +231,7 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Initialize the pwm_chip structure */
|
||||
chip = &priv->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->ops = &sl28cpld_pwm_ops;
|
||||
chip->npwm = 1;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret) {
|
||||
|
@ -48,17 +48,15 @@
|
||||
*
|
||||
* @mmio_base: base address of pwm chip
|
||||
* @clk: pointer to clk structure of pwm chip
|
||||
* @chip: linux pwm chip representation
|
||||
*/
|
||||
struct spear_pwm_chip {
|
||||
void __iomem *mmio_base;
|
||||
struct clk *clk;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct spear_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
|
||||
@ -194,13 +192,15 @@ static const struct pwm_ops spear_pwm_ops = {
|
||||
static int spear_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct pwm_chip *chip;
|
||||
struct spear_pwm_chip *pc;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_spear_pwm_chip(chip);
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
@ -211,9 +211,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
|
||||
"Failed to get clock\n");
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &spear_pwm_ops;
|
||||
pc->chip.npwm = NUM_PWM;
|
||||
chip->ops = &spear_pwm_ops;
|
||||
|
||||
if (of_device_is_compatible(np, "st,spear1340-pwm")) {
|
||||
ret = clk_enable(pc->clk);
|
||||
@ -232,7 +230,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
||||
clk_disable(pc->clk);
|
||||
}
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
|
||||
|
@ -34,15 +34,12 @@ struct sprd_pwm_chn {
|
||||
|
||||
struct sprd_pwm_chip {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct pwm_chip chip;
|
||||
int num_pwms;
|
||||
struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
|
||||
};
|
||||
|
||||
static inline struct sprd_pwm_chip* sprd_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sprd_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -86,7 +83,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
*/
|
||||
ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM, chn->clks);
|
||||
if (ret) {
|
||||
dev_err(spc->dev, "failed to enable pwm%u clocks\n",
|
||||
dev_err(pwmchip_parent(chip), "failed to enable pwm%u clocks\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -183,7 +180,7 @@ static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM,
|
||||
chn->clks);
|
||||
if (ret) {
|
||||
dev_err(spc->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"failed to enable pwm%u clocks\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
@ -215,65 +212,64 @@ static const struct pwm_ops sprd_pwm_ops = {
|
||||
.get_state = sprd_pwm_get_state,
|
||||
};
|
||||
|
||||
static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
|
||||
static int sprd_pwm_clk_init(struct device *dev,
|
||||
struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM])
|
||||
{
|
||||
struct clk *clk_pwm;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < SPRD_PWM_CHN_NUM; i++) {
|
||||
struct sprd_pwm_chn *chn = &spc->chn[i];
|
||||
int j;
|
||||
|
||||
for (j = 0; j < SPRD_PWM_CHN_CLKS_NUM; ++j)
|
||||
chn->clks[j].id =
|
||||
chn[i].clks[j].id =
|
||||
sprd_pwm_clks[i * SPRD_PWM_CHN_CLKS_NUM + j];
|
||||
|
||||
ret = devm_clk_bulk_get(spc->dev, SPRD_PWM_CHN_CLKS_NUM,
|
||||
chn->clks);
|
||||
ret = devm_clk_bulk_get(dev, SPRD_PWM_CHN_CLKS_NUM,
|
||||
chn[i].clks);
|
||||
if (ret) {
|
||||
if (ret == -ENOENT)
|
||||
break;
|
||||
|
||||
return dev_err_probe(spc->dev, ret,
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get channel clocks\n");
|
||||
}
|
||||
|
||||
clk_pwm = chn->clks[SPRD_PWM_CHN_OUTPUT_CLK].clk;
|
||||
chn->clk_rate = clk_get_rate(clk_pwm);
|
||||
clk_pwm = chn[i].clks[SPRD_PWM_CHN_OUTPUT_CLK].clk;
|
||||
chn[i].clk_rate = clk_get_rate(clk_pwm);
|
||||
}
|
||||
|
||||
if (!i)
|
||||
return dev_err_probe(spc->dev, -ENODEV, "no available PWM channels\n");
|
||||
return dev_err_probe(dev, -ENODEV, "no available PWM channels\n");
|
||||
|
||||
spc->num_pwms = i;
|
||||
|
||||
return 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int sprd_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct sprd_pwm_chip *spc;
|
||||
int ret;
|
||||
struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
|
||||
int ret, npwm;
|
||||
|
||||
spc = devm_kzalloc(&pdev->dev, sizeof(*spc), GFP_KERNEL);
|
||||
if (!spc)
|
||||
return -ENOMEM;
|
||||
npwm = sprd_pwm_clk_init(&pdev->dev, chn);
|
||||
if (npwm < 0)
|
||||
return npwm;
|
||||
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*spc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
spc = sprd_pwm_from_chip(chip);
|
||||
|
||||
spc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(spc->base))
|
||||
return PTR_ERR(spc->base);
|
||||
|
||||
spc->dev = &pdev->dev;
|
||||
memcpy(spc->chn, chn, sizeof(chn));
|
||||
|
||||
ret = sprd_pwm_clk_init(spc);
|
||||
if (ret)
|
||||
return ret;
|
||||
chip->ops = &sprd_pwm_ops;
|
||||
|
||||
spc->chip.dev = &pdev->dev;
|
||||
spc->chip.ops = &sprd_pwm_ops;
|
||||
spc->chip.npwm = spc->num_pwms;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &spc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -94,7 +94,6 @@ struct sti_pwm_chip {
|
||||
struct regmap_field *pwm_cpt_en;
|
||||
struct regmap_field *pwm_cpt_int_en;
|
||||
struct regmap_field *pwm_cpt_int_stat;
|
||||
struct pwm_chip chip;
|
||||
struct pwm_device *cur;
|
||||
unsigned long configured;
|
||||
unsigned int en_count;
|
||||
@ -114,7 +113,7 @@ static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
|
||||
|
||||
static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sti_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -395,8 +394,17 @@ out:
|
||||
static int sti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
|
||||
struct sti_pwm_compat_data *cdata = pc->cdata;
|
||||
struct device *dev = pc->dev;
|
||||
int err;
|
||||
|
||||
if (pwm->hwpwm >= cdata->pwm_num_devs) {
|
||||
dev_err(dev, "device %u is not valid for pwm mode\n",
|
||||
pwm->hwpwm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
@ -498,23 +506,7 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
|
||||
{
|
||||
struct device *dev = pc->dev;
|
||||
const struct reg_field *reg_fields;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct sti_pwm_compat_data *cdata = pc->cdata;
|
||||
u32 num_devs;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs);
|
||||
if (!ret)
|
||||
cdata->pwm_num_devs = num_devs;
|
||||
|
||||
ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs);
|
||||
if (!ret)
|
||||
cdata->cpt_num_devs = num_devs;
|
||||
|
||||
if (!cdata->pwm_num_devs && !cdata->cpt_num_devs) {
|
||||
dev_err(dev, "No channels configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg_fields = cdata->reg_fields;
|
||||
|
||||
@ -560,14 +552,33 @@ static const struct regmap_config sti_pwm_regmap_config = {
|
||||
static int sti_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 num_devs;
|
||||
unsigned int pwm_num_devs = 0;
|
||||
unsigned int cpt_num_devs = 0;
|
||||
struct sti_pwm_compat_data *cdata;
|
||||
struct pwm_chip *chip;
|
||||
struct sti_pwm_chip *pc;
|
||||
unsigned int i;
|
||||
int irq, ret;
|
||||
|
||||
pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs);
|
||||
if (!ret)
|
||||
pwm_num_devs = num_devs;
|
||||
|
||||
ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs);
|
||||
if (!ret)
|
||||
cpt_num_devs = num_devs;
|
||||
|
||||
if (!pwm_num_devs && !cpt_num_devs) {
|
||||
dev_err(dev, "No channels configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = devm_pwmchip_alloc(dev, max(pwm_num_devs, cpt_num_devs), sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_sti_pwmchip(chip);
|
||||
|
||||
cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
|
||||
if (!cdata)
|
||||
@ -600,8 +611,8 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
||||
cdata->reg_fields = sti_pwm_regfields;
|
||||
cdata->max_prescale = 0xff;
|
||||
cdata->max_pwm_cnt = 255;
|
||||
cdata->pwm_num_devs = 0;
|
||||
cdata->cpt_num_devs = 0;
|
||||
cdata->pwm_num_devs = pwm_num_devs;
|
||||
cdata->cpt_num_devs = cpt_num_devs;
|
||||
|
||||
pc->cdata = cdata;
|
||||
pc->dev = dev;
|
||||
@ -644,9 +655,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pc->chip.dev = dev;
|
||||
pc->chip.ops = &sti_pwm_ops;
|
||||
pc->chip.npwm = pc->cdata->pwm_num_devs;
|
||||
chip->ops = &sti_pwm_ops;
|
||||
|
||||
for (i = 0; i < cdata->cpt_num_devs; i++) {
|
||||
struct sti_cpt_ddata *ddata = &cdata->ddata[i];
|
||||
@ -655,23 +664,24 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
||||
mutex_init(&ddata->lock);
|
||||
}
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
clk_unprepare(pc->pwm_clk);
|
||||
clk_unprepare(pc->cpt_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sti_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_unprepare(pc->pwm_clk);
|
||||
clk_unprepare(pc->cpt_clk);
|
||||
|
@ -18,14 +18,13 @@
|
||||
#include <linux/pwm.h>
|
||||
|
||||
struct stm32_pwm_lp {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct stm32_pwm_lp, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
|
||||
@ -61,7 +60,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
do_div(div, NSEC_PER_SEC);
|
||||
if (!div) {
|
||||
/* Clock is too slow to achieve requested period. */
|
||||
dev_dbg(priv->chip.dev, "Can't reach %llu ns\n", state->period);
|
||||
dev_dbg(pwmchip_parent(chip), "Can't reach %llu ns\n", state->period);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -69,7 +68,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
while (div > STM32_LPTIM_MAX_ARR) {
|
||||
presc++;
|
||||
if ((1 << presc) > STM32_LPTIM_MAX_PRESCALER) {
|
||||
dev_err(priv->chip.dev, "max prescaler exceeded\n");
|
||||
dev_err(pwmchip_parent(chip), "max prescaler exceeded\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
div = prd >> presc;
|
||||
@ -130,7 +129,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
(val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
|
||||
100, 1000);
|
||||
if (ret) {
|
||||
dev_err(priv->chip.dev, "ARR/CMP registers write issue\n");
|
||||
dev_err(pwmchip_parent(chip), "ARR/CMP registers write issue\n");
|
||||
goto err;
|
||||
}
|
||||
ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,
|
||||
@ -197,36 +196,36 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
|
||||
struct stm32_pwm_lp *priv;
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = to_stm32_pwm_lp(chip);
|
||||
|
||||
priv->regmap = ddata->regmap;
|
||||
priv->clk = ddata->clk;
|
||||
priv->chip.dev = &pdev->dev;
|
||||
priv->chip.ops = &stm32_pwm_lp_ops;
|
||||
priv->chip.npwm = 1;
|
||||
chip->ops = &stm32_pwm_lp_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_pwm_lp_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_pwm_lp *priv = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct pwm_state state;
|
||||
|
||||
pwm_get_state(&priv->chip.pwms[0], &state);
|
||||
pwm_get_state(&chip->pwms[0], &state);
|
||||
if (state.enabled) {
|
||||
dev_err(dev, "The consumer didn't stop us (%s)\n",
|
||||
priv->chip.pwms[0].label);
|
||||
chip->pwms[0].label);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ struct stm32_breakinput {
|
||||
};
|
||||
|
||||
struct stm32_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct mutex lock; /* protect pwm config/enable */
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
@ -40,7 +39,7 @@ struct stm32_pwm {
|
||||
|
||||
static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct stm32_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static u32 active_channels(struct stm32_pwm *dev)
|
||||
@ -90,11 +89,12 @@ static u32 active_channels(struct stm32_pwm *dev)
|
||||
* - Period = t2 - t0
|
||||
* - Duty cycle = t1 - t0
|
||||
*/
|
||||
static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm,
|
||||
static int stm32_pwm_raw_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long tmo_ms, u32 *raw_prd,
|
||||
u32 *raw_dty)
|
||||
{
|
||||
struct device *parent = priv->chip.dev->parent;
|
||||
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
|
||||
struct device *parent = pwmchip_parent(chip)->parent;
|
||||
enum stm32_timers_dmas dma_id;
|
||||
u32 ccen, ccr;
|
||||
int ret;
|
||||
@ -170,7 +170,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = clk_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(priv->chip.dev, "failed to enable counter clock\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to enable counter clock\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@ -208,7 +208,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
TIM_CCER_CC12P : TIM_CCER_CC34P, pwm->hwpwm < 2 ?
|
||||
TIM_CCER_CC2P : TIM_CCER_CC4P);
|
||||
|
||||
ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty);
|
||||
ret = stm32_pwm_raw_capture(chip, pwm, tmo_ms, &raw_prd, &raw_dty);
|
||||
if (ret)
|
||||
goto stop;
|
||||
|
||||
@ -229,7 +229,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
/* 2nd measure with new scale */
|
||||
psc /= scale;
|
||||
regmap_write(priv->regmap, TIM_PSC, psc);
|
||||
ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd,
|
||||
ret = stm32_pwm_raw_capture(chip, pwm, tmo_ms, &raw_prd,
|
||||
&raw_dty);
|
||||
if (ret)
|
||||
goto stop;
|
||||
@ -257,7 +257,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
FIELD_PREP(TIM_CCMR_IC1PSC, icpsc) |
|
||||
FIELD_PREP(TIM_CCMR_IC2PSC, icpsc));
|
||||
|
||||
ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty);
|
||||
ret = stm32_pwm_raw_capture(chip, pwm, tmo_ms, &raw_prd, &raw_dty);
|
||||
if (ret)
|
||||
goto stop;
|
||||
|
||||
@ -605,7 +605,7 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
|
||||
priv->have_complementary_output = (ccer != 0);
|
||||
}
|
||||
|
||||
static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
|
||||
static unsigned int stm32_pwm_detect_channels(struct regmap *regmap,
|
||||
unsigned int *num_enabled)
|
||||
{
|
||||
u32 ccer, ccer_backup;
|
||||
@ -614,10 +614,10 @@ static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
|
||||
* If channels enable bits don't exist writing 1 will have no
|
||||
* effect so we can detect and count them.
|
||||
*/
|
||||
regmap_read(priv->regmap, TIM_CCER, &ccer_backup);
|
||||
regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
|
||||
regmap_read(priv->regmap, TIM_CCER, &ccer);
|
||||
regmap_write(priv->regmap, TIM_CCER, ccer_backup);
|
||||
regmap_read(regmap, TIM_CCER, &ccer_backup);
|
||||
regmap_set_bits(regmap, TIM_CCER, TIM_CCER_CCXE);
|
||||
regmap_read(regmap, TIM_CCER, &ccer);
|
||||
regmap_write(regmap, TIM_CCER, ccer_backup);
|
||||
|
||||
*num_enabled = hweight32(ccer_backup & TIM_CCER_CCXE);
|
||||
|
||||
@ -629,14 +629,18 @@ static int stm32_pwm_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pwm_chip *chip;
|
||||
struct stm32_pwm *priv;
|
||||
unsigned int num_enabled;
|
||||
unsigned int npwm, num_enabled;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
npwm = stm32_pwm_detect_channels(ddata->regmap, &num_enabled);
|
||||
|
||||
chip = devm_pwmchip_alloc(dev, npwm, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = to_stm32_pwm_dev(chip);
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
priv->regmap = ddata->regmap;
|
||||
@ -652,37 +656,36 @@ static int stm32_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
stm32_pwm_detect_complementary(priv);
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &stm32pwm_ops;
|
||||
priv->chip.npwm = stm32_pwm_detect_channels(priv, &num_enabled);
|
||||
chip->ops = &stm32pwm_ops;
|
||||
|
||||
/* Initialize clock refcount to number of enabled PWM channels. */
|
||||
for (i = 0; i < num_enabled; i++)
|
||||
clk_enable(priv->clk);
|
||||
|
||||
ret = devm_pwmchip_add(dev, &priv->chip);
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32_pwm *priv = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
|
||||
unsigned int i;
|
||||
u32 ccer, mask;
|
||||
|
||||
/* Look for active channels */
|
||||
ccer = active_channels(priv);
|
||||
|
||||
for (i = 0; i < priv->chip.npwm; i++) {
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
mask = TIM_CCER_CC1E << (i * 4);
|
||||
if (ccer & mask) {
|
||||
dev_err(dev, "PWM %u still in use by consumer %s\n",
|
||||
i, priv->chip.pwms[i].label);
|
||||
i, chip->pwms[i].label);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
@ -692,7 +695,8 @@ static int stm32_pwm_suspend(struct device *dev)
|
||||
|
||||
static int stm32_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct stm32_pwm *priv = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(dev);
|
||||
|
@ -27,13 +27,12 @@
|
||||
|
||||
struct stmpe_pwm {
|
||||
struct stmpe *stmpe;
|
||||
struct pwm_chip chip;
|
||||
u8 last_duty;
|
||||
};
|
||||
|
||||
static inline struct stmpe_pwm *to_stmpe_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct stmpe_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -44,7 +43,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
|
||||
if (ret < 0) {
|
||||
dev_dbg(chip->dev, "error reading PWM#%u control\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error reading PWM#%u control\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -53,7 +52,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
|
||||
if (ret) {
|
||||
dev_dbg(chip->dev, "error writing PWM#%u control\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error writing PWM#%u control\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -70,7 +69,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
|
||||
|
||||
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
|
||||
if (ret < 0) {
|
||||
dev_dbg(chip->dev, "error reading PWM#%u control\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error reading PWM#%u control\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -79,7 +78,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
|
||||
|
||||
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
|
||||
if (ret)
|
||||
dev_dbg(chip->dev, "error writing PWM#%u control\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error writing PWM#%u control\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -125,7 +124,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ret = stmpe_set_altfunc(stmpe_pwm->stmpe, BIT(pin),
|
||||
STMPE_BLOCK_PWM);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "unable to connect PWM#%u to pin\n",
|
||||
dev_err(pwmchip_parent(chip), "unable to connect PWM#%u to pin\n",
|
||||
pwm->hwpwm);
|
||||
return ret;
|
||||
}
|
||||
@ -150,7 +149,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_dbg(chip->dev, "PWM#%u: config duty %d ns, period %d ns\n",
|
||||
dev_dbg(pwmchip_parent(chip), "PWM#%u: config duty %d ns, period %d ns\n",
|
||||
pwm->hwpwm, duty_ns, period_ns);
|
||||
|
||||
if (duty_ns == 0) {
|
||||
@ -216,7 +215,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
program[1] = BRANCH;
|
||||
}
|
||||
|
||||
dev_dbg(chip->dev,
|
||||
dev_dbg(pwmchip_parent(chip),
|
||||
"PWM#%u: value = %02x, last_duty = %02x, program=%04x,%04x,%04x\n",
|
||||
pwm->hwpwm, value, last, program[0], program[1],
|
||||
program[2]);
|
||||
@ -233,7 +232,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
|
||||
if (ret) {
|
||||
dev_dbg(chip->dev, "error writing register %02x: %d\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error writing register %02x: %d\n",
|
||||
offset, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -242,7 +241,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
|
||||
if (ret) {
|
||||
dev_dbg(chip->dev, "error writing register %02x: %d\n",
|
||||
dev_dbg(pwmchip_parent(chip), "error writing register %02x: %d\n",
|
||||
offset, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -255,7 +254,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
/* Sleep for 200ms so we're sure it will take effect */
|
||||
msleep(200);
|
||||
|
||||
dev_dbg(chip->dev, "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i);
|
||||
dev_dbg(pwmchip_parent(chip), "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -292,33 +291,36 @@ static const struct pwm_ops stmpe_24xx_pwm_ops = {
|
||||
static int __init stmpe_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pwm_chip *chip;
|
||||
struct stmpe_pwm *stmpe_pwm;
|
||||
int ret;
|
||||
|
||||
stmpe_pwm = devm_kzalloc(&pdev->dev, sizeof(*stmpe_pwm), GFP_KERNEL);
|
||||
if (!stmpe_pwm)
|
||||
return -ENOMEM;
|
||||
switch (stmpe->partnum) {
|
||||
case STMPE2401:
|
||||
case STMPE2403:
|
||||
break;
|
||||
case STMPE1601:
|
||||
return dev_err_probe(&pdev->dev, -ENODEV,
|
||||
"STMPE1601 not yet supported\n");
|
||||
default:
|
||||
return dev_err_probe(&pdev->dev, -ENODEV,
|
||||
"Unknown STMPE PWM\n");
|
||||
}
|
||||
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 3, sizeof(*stmpe_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
stmpe_pwm = to_stmpe_pwm(chip);
|
||||
|
||||
stmpe_pwm->stmpe = stmpe;
|
||||
stmpe_pwm->chip.dev = &pdev->dev;
|
||||
|
||||
if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) {
|
||||
stmpe_pwm->chip.ops = &stmpe_24xx_pwm_ops;
|
||||
stmpe_pwm->chip.npwm = 3;
|
||||
} else {
|
||||
if (stmpe->partnum == STMPE1601)
|
||||
dev_err(&pdev->dev, "STMPE1601 not yet supported\n");
|
||||
else
|
||||
dev_err(&pdev->dev, "Unknown STMPE PWM\n");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
chip->ops = &stmpe_24xx_pwm_ops;
|
||||
|
||||
ret = stmpe_enable(stmpe, STMPE_BLOCK_PWM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pwmchip_add(&stmpe_pwm->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret) {
|
||||
stmpe_disable(stmpe, STMPE_BLOCK_PWM);
|
||||
return ret;
|
||||
|
@ -81,7 +81,6 @@ struct sun4i_pwm_data {
|
||||
};
|
||||
|
||||
struct sun4i_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *bus_clk;
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
@ -92,35 +91,35 @@ struct sun4i_pwm_chip {
|
||||
|
||||
static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sun4i_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *chip,
|
||||
static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *sun4ichip,
|
||||
unsigned long offset)
|
||||
{
|
||||
return readl(chip->base + offset);
|
||||
return readl(sun4ichip->base + offset);
|
||||
}
|
||||
|
||||
static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
|
||||
static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *sun4ichip,
|
||||
u32 val, unsigned long offset)
|
||||
{
|
||||
writel(val, chip->base + offset);
|
||||
writel(val, sun4ichip->base + offset);
|
||||
}
|
||||
|
||||
static int sun4i_pwm_get_state(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
|
||||
struct sun4i_pwm_chip *sun4ichip = to_sun4i_pwm_chip(chip);
|
||||
u64 clk_rate, tmp;
|
||||
u32 val;
|
||||
unsigned int prescaler;
|
||||
|
||||
clk_rate = clk_get_rate(sun4i_pwm->clk);
|
||||
clk_rate = clk_get_rate(sun4ichip->clk);
|
||||
if (!clk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
|
||||
val = sun4i_pwm_readl(sun4ichip, PWM_CTRL_REG);
|
||||
|
||||
/*
|
||||
* PWM chapter in H6 manual has a diagram which explains that if bypass
|
||||
@ -128,7 +127,7 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip,
|
||||
* proved that also enable bit is ignored in this case.
|
||||
*/
|
||||
if ((val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) &&
|
||||
sun4i_pwm->data->has_direct_mod_clk_output) {
|
||||
sun4ichip->data->has_direct_mod_clk_output) {
|
||||
state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate);
|
||||
state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2);
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
@ -137,7 +136,7 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip,
|
||||
}
|
||||
|
||||
if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) &&
|
||||
sun4i_pwm->data->has_prescaler_bypass)
|
||||
sun4ichip->data->has_prescaler_bypass)
|
||||
prescaler = 1;
|
||||
else
|
||||
prescaler = prescaler_table[PWM_REG_PRESCAL(val, pwm->hwpwm)];
|
||||
@ -156,7 +155,7 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip,
|
||||
else
|
||||
state->enabled = false;
|
||||
|
||||
val = sun4i_pwm_readl(sun4i_pwm, PWM_CH_PRD(pwm->hwpwm));
|
||||
val = sun4i_pwm_readl(sun4ichip, PWM_CH_PRD(pwm->hwpwm));
|
||||
|
||||
tmp = (u64)prescaler * NSEC_PER_SEC * PWM_REG_DTY(val);
|
||||
state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
|
||||
@ -167,7 +166,7 @@ static int sun4i_pwm_get_state(struct pwm_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
|
||||
static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4ichip,
|
||||
const struct pwm_state *state,
|
||||
u32 *dty, u32 *prd, unsigned int *prsclr,
|
||||
bool *bypass)
|
||||
@ -175,9 +174,9 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
|
||||
u64 clk_rate, div = 0;
|
||||
unsigned int prescaler = 0;
|
||||
|
||||
clk_rate = clk_get_rate(sun4i_pwm->clk);
|
||||
clk_rate = clk_get_rate(sun4ichip->clk);
|
||||
|
||||
*bypass = sun4i_pwm->data->has_direct_mod_clk_output &&
|
||||
*bypass = sun4ichip->data->has_direct_mod_clk_output &&
|
||||
state->enabled &&
|
||||
(state->period * clk_rate >= NSEC_PER_SEC) &&
|
||||
(state->period * clk_rate < 2 * NSEC_PER_SEC) &&
|
||||
@ -187,7 +186,7 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
|
||||
if (*bypass)
|
||||
return 0;
|
||||
|
||||
if (sun4i_pwm->data->has_prescaler_bypass) {
|
||||
if (sun4ichip->data->has_prescaler_bypass) {
|
||||
/* First, test without any prescaler when available */
|
||||
prescaler = PWM_PRESCAL_MASK;
|
||||
/*
|
||||
@ -233,7 +232,7 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm,
|
||||
static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
|
||||
struct sun4i_pwm_chip *sun4ichip = to_sun4i_pwm_chip(chip);
|
||||
struct pwm_state cstate;
|
||||
u32 ctrl, duty = 0, period = 0, val;
|
||||
int ret;
|
||||
@ -243,31 +242,31 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
pwm_get_state(pwm, &cstate);
|
||||
|
||||
if (!cstate.enabled) {
|
||||
ret = clk_prepare_enable(sun4i_pwm->clk);
|
||||
ret = clk_prepare_enable(sun4ichip->clk);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "failed to enable PWM clock\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to enable PWM clock\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler,
|
||||
ret = sun4i_pwm_calculate(sun4ichip, state, &duty, &period, &prescaler,
|
||||
&bypass);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "period exceeds the maximum value\n");
|
||||
dev_err(pwmchip_parent(chip), "period exceeds the maximum value\n");
|
||||
if (!cstate.enabled)
|
||||
clk_disable_unprepare(sun4i_pwm->clk);
|
||||
clk_disable_unprepare(sun4ichip->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock(&sun4i_pwm->ctrl_lock);
|
||||
ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
|
||||
spin_lock(&sun4ichip->ctrl_lock);
|
||||
ctrl = sun4i_pwm_readl(sun4ichip, PWM_CTRL_REG);
|
||||
|
||||
if (sun4i_pwm->data->has_direct_mod_clk_output) {
|
||||
if (sun4ichip->data->has_direct_mod_clk_output) {
|
||||
if (bypass) {
|
||||
ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm);
|
||||
/* We can skip other parameter */
|
||||
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
|
||||
spin_unlock(&sun4i_pwm->ctrl_lock);
|
||||
sun4i_pwm_writel(sun4ichip, ctrl, PWM_CTRL_REG);
|
||||
spin_unlock(&sun4ichip->ctrl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -277,14 +276,14 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) {
|
||||
/* Prescaler changed, the clock has to be gated */
|
||||
ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
|
||||
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
|
||||
sun4i_pwm_writel(sun4ichip, ctrl, PWM_CTRL_REG);
|
||||
|
||||
ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
|
||||
ctrl |= BIT_CH(prescaler, pwm->hwpwm);
|
||||
}
|
||||
|
||||
val = (duty & PWM_DTY_MASK) | PWM_PRD(period);
|
||||
sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
|
||||
sun4i_pwm_writel(sun4ichip, val, PWM_CH_PRD(pwm->hwpwm));
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
|
||||
@ -296,9 +295,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (state->enabled)
|
||||
ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
|
||||
|
||||
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
|
||||
sun4i_pwm_writel(sun4ichip, ctrl, PWM_CTRL_REG);
|
||||
|
||||
spin_unlock(&sun4i_pwm->ctrl_lock);
|
||||
spin_unlock(&sun4ichip->ctrl_lock);
|
||||
|
||||
if (state->enabled)
|
||||
return 0;
|
||||
@ -310,14 +309,14 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
else
|
||||
usleep_range(delay_us, delay_us * 2);
|
||||
|
||||
spin_lock(&sun4i_pwm->ctrl_lock);
|
||||
ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
|
||||
spin_lock(&sun4ichip->ctrl_lock);
|
||||
ctrl = sun4i_pwm_readl(sun4ichip, PWM_CTRL_REG);
|
||||
ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
|
||||
ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm);
|
||||
sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);
|
||||
spin_unlock(&sun4i_pwm->ctrl_lock);
|
||||
sun4i_pwm_writel(sun4ichip, ctrl, PWM_CTRL_REG);
|
||||
spin_unlock(&sun4ichip->ctrl_lock);
|
||||
|
||||
clk_disable_unprepare(sun4i_pwm->clk);
|
||||
clk_disable_unprepare(sun4ichip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -384,17 +383,21 @@ MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
|
||||
|
||||
static int sun4i_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
const struct sun4i_pwm_data *data;
|
||||
struct sun4i_pwm_chip *sun4ichip;
|
||||
int ret;
|
||||
|
||||
sun4ichip = devm_kzalloc(&pdev->dev, sizeof(*sun4ichip), GFP_KERNEL);
|
||||
if (!sun4ichip)
|
||||
return -ENOMEM;
|
||||
|
||||
sun4ichip->data = of_device_get_match_data(&pdev->dev);
|
||||
if (!sun4ichip->data)
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, data->npwm, sizeof(*sun4ichip));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
sun4ichip = to_sun4i_pwm_chip(chip);
|
||||
|
||||
sun4ichip->data = data;
|
||||
sun4ichip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sun4ichip->base))
|
||||
return PTR_ERR(sun4ichip->base);
|
||||
@ -451,19 +454,17 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
|
||||
goto err_bus;
|
||||
}
|
||||
|
||||
sun4ichip->chip.dev = &pdev->dev;
|
||||
sun4ichip->chip.ops = &sun4i_pwm_ops;
|
||||
sun4ichip->chip.npwm = sun4ichip->data->npwm;
|
||||
chip->ops = &sun4i_pwm_ops;
|
||||
|
||||
spin_lock_init(&sun4ichip->ctrl_lock);
|
||||
|
||||
ret = pwmchip_add(&sun4ichip->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
goto err_pwm_add;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, sun4ichip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -477,9 +478,10 @@ err_bus:
|
||||
|
||||
static void sun4i_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sun4i_pwm_chip *sun4ichip = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct sun4i_pwm_chip *sun4ichip = to_sun4i_pwm_chip(chip);
|
||||
|
||||
pwmchip_remove(&sun4ichip->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_disable_unprepare(sun4ichip->bus_clk);
|
||||
reset_control_assert(sun4ichip->rst);
|
||||
|
@ -43,14 +43,13 @@
|
||||
#define SP7021_PWM_NUM 4
|
||||
|
||||
struct sunplus_pwm {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline struct sunplus_pwm *to_sunplus_pwm(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sunplus_pwm, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int sunplus_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -175,12 +174,14 @@ static void sunplus_pwm_clk_release(void *data)
|
||||
static int sunplus_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_chip *chip;
|
||||
struct sunplus_pwm *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, SP7021_PWM_NUM, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = to_sunplus_pwm(chip);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
@ -203,11 +204,9 @@ static int sunplus_pwm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &sunplus_pwm_ops;
|
||||
priv->chip.npwm = SP7021_PWM_NUM;
|
||||
chip->ops = &sunplus_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(dev, &priv->chip);
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Cannot register sunplus PWM\n");
|
||||
|
||||
|
@ -65,9 +65,6 @@ struct tegra_pwm_soc {
|
||||
};
|
||||
|
||||
struct tegra_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct device *dev;
|
||||
|
||||
struct clk *clk;
|
||||
struct reset_control*rst;
|
||||
|
||||
@ -81,7 +78,7 @@ struct tegra_pwm_chip {
|
||||
|
||||
static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct tegra_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u32 pwm_readl(struct tegra_pwm_chip *pc, unsigned int offset)
|
||||
@ -158,7 +155,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
*/
|
||||
required_clk_rate *= 2;
|
||||
|
||||
err = dev_pm_opp_set_rate(pc->dev, required_clk_rate);
|
||||
err = dev_pm_opp_set_rate(pwmchip_parent(chip), required_clk_rate);
|
||||
if (err < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -194,7 +191,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* before writing the register. Otherwise, keep it enabled.
|
||||
*/
|
||||
if (!pwm_is_enabled(pwm)) {
|
||||
err = pm_runtime_resume_and_get(pc->dev);
|
||||
err = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
@ -206,7 +203,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* If the PWM is not enabled, turn the clock off again to save power.
|
||||
*/
|
||||
if (!pwm_is_enabled(pwm))
|
||||
pm_runtime_put(pc->dev);
|
||||
pm_runtime_put(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -217,7 +214,7 @@ static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
int rc = 0;
|
||||
u32 val;
|
||||
|
||||
rc = pm_runtime_resume_and_get(pc->dev);
|
||||
rc = pm_runtime_resume_and_get(pwmchip_parent(chip));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -237,7 +234,7 @@ static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
val &= ~PWM_ENABLE;
|
||||
pwm_writel(pc, pwm->hwpwm, val);
|
||||
|
||||
pm_runtime_put_sync(pc->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -272,21 +269,25 @@ static const struct pwm_ops tegra_pwm_ops = {
|
||||
|
||||
static int tegra_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct tegra_pwm_chip *pc;
|
||||
const struct tegra_pwm_soc *soc;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
pc->soc = of_device_get_match_data(&pdev->dev);
|
||||
pc->dev = &pdev->dev;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, soc->num_channels, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_tegra_pwm_chip(chip);
|
||||
|
||||
pc->soc = soc;
|
||||
|
||||
pc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->regs))
|
||||
return PTR_ERR(pc->regs);
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pc->clk))
|
||||
@ -302,7 +303,7 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
/* Set maximum frequency of the IP */
|
||||
ret = dev_pm_opp_set_rate(pc->dev, pc->soc->max_frequency);
|
||||
ret = dev_pm_opp_set_rate(&pdev->dev, pc->soc->max_frequency);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret);
|
||||
goto put_pm;
|
||||
@ -328,11 +329,9 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
reset_control_deassert(pc->rst);
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &tegra_pwm_ops;
|
||||
pc->chip.npwm = pc->soc->num_channels;
|
||||
chip->ops = &tegra_pwm_ops;
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
reset_control_assert(pc->rst);
|
||||
@ -350,9 +349,10 @@ put_pm:
|
||||
|
||||
static void tegra_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
reset_control_assert(pc->rst);
|
||||
|
||||
@ -361,7 +361,8 @@ static void tegra_pwm_remove(struct platform_device *pdev)
|
||||
|
||||
static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
|
||||
int err;
|
||||
|
||||
clk_disable_unprepare(pc->clk);
|
||||
@ -377,7 +378,8 @@ static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev)
|
||||
|
||||
static int __maybe_unused tegra_pwm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
|
||||
int err;
|
||||
|
||||
err = pinctrl_pm_select_default_state(dev);
|
||||
|
@ -32,7 +32,6 @@ struct ecap_context {
|
||||
};
|
||||
|
||||
struct ecap_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
unsigned int clk_rate;
|
||||
void __iomem *mmio_base;
|
||||
struct ecap_context ctx;
|
||||
@ -40,7 +39,7 @@ struct ecap_pwm_chip {
|
||||
|
||||
static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ecap_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -70,7 +69,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
duty_cycles = (u32)c;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
value = readw(pc->mmio_base + ECCTL2);
|
||||
|
||||
@ -100,7 +99,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
writew(value, pc->mmio_base + ECCTL2);
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(pc->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -111,7 +110,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
|
||||
u16 value;
|
||||
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
value = readw(pc->mmio_base + ECCTL2);
|
||||
|
||||
@ -124,7 +123,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
writew(value, pc->mmio_base + ECCTL2);
|
||||
|
||||
pm_runtime_put_sync(pc->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -135,7 +134,7 @@ static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
u16 value;
|
||||
|
||||
/* Leave clock enabled on enabling PWM */
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
/*
|
||||
* Enable 'Free run Time stamp counter mode' to start counter
|
||||
@ -162,7 +161,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
writew(value, pc->mmio_base + ECCTL2);
|
||||
|
||||
/* Disable clock on PWM disable */
|
||||
pm_runtime_put_sync(pc->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -218,12 +217,14 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ecap_pwm_chip *pc;
|
||||
struct pwm_chip *chip;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_ecap_pwm_chip(chip);
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
@ -244,21 +245,19 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &ecap_pwm_ops;
|
||||
pc->chip.npwm = 1;
|
||||
chip->ops = &ecap_pwm_ops;
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
return PTR_ERR(pc->mmio_base);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
@ -269,17 +268,21 @@ static void ecap_pwm_remove(struct platform_device *pdev)
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
|
||||
static void ecap_pwm_save_context(struct pwm_chip *chip)
|
||||
{
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
|
||||
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2);
|
||||
pc->ctx.cap4 = readl(pc->mmio_base + CAP4);
|
||||
pc->ctx.cap3 = readl(pc->mmio_base + CAP3);
|
||||
pm_runtime_put_sync(pc->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
|
||||
static void ecap_pwm_restore_context(struct pwm_chip *chip)
|
||||
{
|
||||
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
|
||||
|
||||
writel(pc->ctx.cap3, pc->mmio_base + CAP3);
|
||||
writel(pc->ctx.cap4, pc->mmio_base + CAP4);
|
||||
writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2);
|
||||
@ -287,10 +290,10 @@ static void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
|
||||
|
||||
static int ecap_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_device *pwm = pc->chip.pwms;
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct pwm_device *pwm = chip->pwms;
|
||||
|
||||
ecap_pwm_save_context(pc);
|
||||
ecap_pwm_save_context(chip);
|
||||
|
||||
/* Disable explicitly if PWM is running */
|
||||
if (pwm_is_enabled(pwm))
|
||||
@ -301,14 +304,14 @@ static int ecap_pwm_suspend(struct device *dev)
|
||||
|
||||
static int ecap_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_device *pwm = pc->chip.pwms;
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct pwm_device *pwm = chip->pwms;
|
||||
|
||||
/* Enable explicitly if PWM was running */
|
||||
if (pwm_is_enabled(pwm))
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
ecap_pwm_restore_context(pc);
|
||||
ecap_pwm_restore_context(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,6 @@ struct ehrpwm_context {
|
||||
};
|
||||
|
||||
struct ehrpwm_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
unsigned long clk_rate;
|
||||
void __iomem *mmio_base;
|
||||
unsigned long period_cycles[NUM_PWM_CHANNEL];
|
||||
@ -116,7 +115,7 @@ struct ehrpwm_pwm_chip {
|
||||
|
||||
static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ehrpwm_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static inline u16 ehrpwm_read(void __iomem *base, unsigned int offset)
|
||||
@ -256,7 +255,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (i == pwm->hwpwm)
|
||||
continue;
|
||||
|
||||
dev_err(chip->dev,
|
||||
dev_err(pwmchip_parent(chip),
|
||||
"period value conflicts with channel %u\n",
|
||||
i);
|
||||
return -EINVAL;
|
||||
@ -268,11 +267,11 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
/* Configure clock prescaler to support Low frequency PWM wave */
|
||||
if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
|
||||
&tb_divval)) {
|
||||
dev_err(chip->dev, "Unsupported values\n");
|
||||
dev_err(pwmchip_parent(chip), "Unsupported values\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
/* Update clock prescaler values */
|
||||
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval);
|
||||
@ -299,7 +298,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
|
||||
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -323,7 +322,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
int ret;
|
||||
|
||||
/* Leave clock enabled on enabling PWM */
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
/* Disabling Action Qualifier on PWM output */
|
||||
if (pwm->hwpwm) {
|
||||
@ -346,8 +345,8 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
/* Enable TBCLK */
|
||||
ret = clk_enable(pc->tbclk);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to enable TBCLK for %s: %d\n",
|
||||
dev_name(pc->chip.dev), ret);
|
||||
dev_err(pwmchip_parent(chip), "Failed to enable TBCLK for %s: %d\n",
|
||||
dev_name(pwmchip_parent(chip)), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -385,7 +384,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
clk_disable(pc->tbclk);
|
||||
|
||||
/* Disable clock on PWM disable */
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
@ -393,8 +392,8 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
|
||||
|
||||
if (pwm_is_enabled(pwm)) {
|
||||
dev_warn(chip->dev, "Removing PWM device without disabling\n");
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
dev_warn(pwmchip_parent(chip), "Removing PWM device without disabling\n");
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
/* set period value to zero on free */
|
||||
@ -450,12 +449,14 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ehrpwm_pwm_chip *pc;
|
||||
struct pwm_chip *chip;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (!pc)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
pc = to_ehrpwm_pwm_chip(chip);
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
@ -474,9 +475,7 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &ehrpwm_pwm_ops;
|
||||
pc->chip.npwm = NUM_PWM_CHANNEL;
|
||||
chip->ops = &ehrpwm_pwm_ops;
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
@ -493,13 +492,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
goto err_clk_unprepare;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
@ -512,18 +511,21 @@ err_clk_unprepare:
|
||||
|
||||
static void ehrpwm_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
clk_unprepare(pc->tbclk);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
|
||||
static void ehrpwm_pwm_save_context(struct pwm_chip *chip)
|
||||
{
|
||||
pm_runtime_get_sync(pc->chip.dev);
|
||||
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
|
||||
|
||||
pm_runtime_get_sync(pwmchip_parent(chip));
|
||||
|
||||
pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);
|
||||
pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);
|
||||
@ -534,11 +536,13 @@ static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
|
||||
pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);
|
||||
pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);
|
||||
|
||||
pm_runtime_put_sync(pc->chip.dev);
|
||||
pm_runtime_put_sync(pwmchip_parent(chip));
|
||||
}
|
||||
|
||||
static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
|
||||
static void ehrpwm_pwm_restore_context(struct pwm_chip *chip)
|
||||
{
|
||||
struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
|
||||
|
||||
ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd);
|
||||
ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa);
|
||||
ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb);
|
||||
@ -551,13 +555,13 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
|
||||
|
||||
static int ehrpwm_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
ehrpwm_pwm_save_context(pc);
|
||||
ehrpwm_pwm_save_context(chip);
|
||||
|
||||
for (i = 0; i < pc->chip.npwm; i++) {
|
||||
struct pwm_device *pwm = &pc->chip.pwms[i];
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
if (!pwm_is_enabled(pwm))
|
||||
continue;
|
||||
@ -571,11 +575,11 @@ static int ehrpwm_pwm_suspend(struct device *dev)
|
||||
|
||||
static int ehrpwm_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pc->chip.npwm; i++) {
|
||||
struct pwm_device *pwm = &pc->chip.pwms[i];
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
|
||||
if (!pwm_is_enabled(pwm))
|
||||
continue;
|
||||
@ -584,7 +588,7 @@ static int ehrpwm_pwm_resume(struct device *dev)
|
||||
pm_runtime_get_sync(dev);
|
||||
}
|
||||
|
||||
ehrpwm_pwm_restore_context(pc);
|
||||
ehrpwm_pwm_restore_context(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -62,13 +62,12 @@
|
||||
#define TWL6040_LED_MODE_MASK 0x03
|
||||
|
||||
struct twl_pwmled_chip {
|
||||
struct pwm_chip chip;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct twl_pwmled_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -100,7 +99,7 @@ static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to configure PWM\n", pwm->label);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -114,7 +113,7 @@ static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read LEDEN\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -122,7 +121,7 @@ static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -139,7 +138,7 @@ static void twl4030_pwmled_disable(struct pwm_chip *chip,
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read LEDEN\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -147,7 +146,7 @@ static void twl4030_pwmled_disable(struct pwm_chip *chip,
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -203,7 +202,7 @@ static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
|
||||
TWL6030_LED_PWM_CTRL1);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to configure PWM\n", pwm->label);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -217,7 +216,7 @@ static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PWM_CTRL2\n",
|
||||
pwm->label);
|
||||
goto out;
|
||||
}
|
||||
@ -227,7 +226,7 @@ static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -244,7 +243,7 @@ static void twl6030_pwmled_disable(struct pwm_chip *chip,
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PWM_CTRL2\n",
|
||||
pwm->label);
|
||||
goto out;
|
||||
}
|
||||
@ -254,7 +253,7 @@ static void twl6030_pwmled_disable(struct pwm_chip *chip,
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -295,7 +294,7 @@ static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PWM_CTRL2\n",
|
||||
pwm->label);
|
||||
goto out;
|
||||
}
|
||||
@ -305,7 +304,7 @@ static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to request PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -321,7 +320,7 @@ static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PWM_CTRL2\n",
|
||||
pwm->label);
|
||||
goto out;
|
||||
}
|
||||
@ -331,7 +330,7 @@ static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to free PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -345,25 +344,29 @@ static const struct pwm_ops twl6030_pwmled_ops = {
|
||||
|
||||
static int twl_pwmled_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct twl_pwmled_chip *twl;
|
||||
|
||||
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
|
||||
if (!twl)
|
||||
return -ENOMEM;
|
||||
unsigned int npwm;
|
||||
const struct pwm_ops *ops;
|
||||
|
||||
if (twl_class_is_4030()) {
|
||||
twl->chip.ops = &twl4030_pwmled_ops;
|
||||
twl->chip.npwm = 2;
|
||||
ops = &twl4030_pwmled_ops;
|
||||
npwm = 2;
|
||||
} else {
|
||||
twl->chip.ops = &twl6030_pwmled_ops;
|
||||
twl->chip.npwm = 1;
|
||||
ops = &twl6030_pwmled_ops;
|
||||
npwm = 1;
|
||||
}
|
||||
|
||||
twl->chip.dev = &pdev->dev;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*twl));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
twl = to_twl(chip);
|
||||
|
||||
chip->ops = ops;
|
||||
|
||||
mutex_init(&twl->mutex);
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &twl->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@ -46,7 +46,6 @@
|
||||
#define TWL6030_PWM_TOGGLE(pwm, x) ((x) << (pwm * 3))
|
||||
|
||||
struct twl_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct mutex mutex;
|
||||
u8 twl6030_toggle3;
|
||||
u8 twl4030_pwm_mux;
|
||||
@ -54,7 +53,7 @@ struct twl_pwm_chip {
|
||||
|
||||
static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct twl_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -86,7 +85,7 @@ static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to configure PWM\n", pwm->label);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -100,7 +99,7 @@ static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read GPBR1\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -108,13 +107,13 @@ static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM\n", pwm->label);
|
||||
|
||||
val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -130,7 +129,7 @@ static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read GPBR1\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -138,13 +137,13 @@ static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
|
||||
val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -167,7 +166,7 @@ static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PMBR1\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -181,7 +180,7 @@ static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to request PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -202,7 +201,7 @@ static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
mutex_lock(&twl->mutex);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to read PMBR1\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -212,7 +211,7 @@ static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to free PWM\n", pwm->label);
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl->mutex);
|
||||
@ -231,7 +230,7 @@ static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to enable PWM\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -254,7 +253,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
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);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -262,7 +261,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
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);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -270,7 +269,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
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);
|
||||
dev_err(pwmchip_parent(chip), "%s: Failed to disable PWM\n", pwm->label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -341,23 +340,22 @@ static const struct pwm_ops twl6030_pwm_ops = {
|
||||
|
||||
static int twl_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct twl_pwm_chip *twl;
|
||||
|
||||
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
|
||||
if (!twl)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*twl));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
twl = to_twl(chip);
|
||||
|
||||
if (twl_class_is_4030())
|
||||
twl->chip.ops = &twl4030_pwm_ops;
|
||||
chip->ops = &twl4030_pwm_ops;
|
||||
else
|
||||
twl->chip.ops = &twl6030_pwm_ops;
|
||||
|
||||
twl->chip.dev = &pdev->dev;
|
||||
twl->chip.npwm = 2;
|
||||
chip->ops = &twl6030_pwm_ops;
|
||||
|
||||
mutex_init(&twl->mutex);
|
||||
|
||||
return devm_pwmchip_add(&pdev->dev, &twl->chip);
|
||||
return devm_pwmchip_add(&pdev->dev, chip);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@ -34,13 +34,12 @@
|
||||
#define PIPGM_PWMC_POLARITY_MASK GENMASK(5, 5)
|
||||
|
||||
struct visconti_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static inline struct visconti_pwm_chip *visconti_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct visconti_pwm_chip, chip);
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -134,22 +133,22 @@ static const struct pwm_ops visconti_pwm_ops = {
|
||||
static int visconti_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_chip *chip;
|
||||
struct visconti_pwm_chip *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(dev, 4, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = visconti_pwm_from_chip(chip);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &visconti_pwm_ops;
|
||||
priv->chip.npwm = 4;
|
||||
chip->ops = &visconti_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Cannot register visconti PWM\n");
|
||||
|
||||
|
@ -45,16 +45,19 @@
|
||||
#define STATUS_ALL_UPDATE 0x0F
|
||||
|
||||
struct vt8500_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
#define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip)
|
||||
static inline struct vt8500_chip *to_vt8500_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
|
||||
static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask)
|
||||
static inline void vt8500_pwm_busy_wait(struct pwm_chip *chip, int nr, u8 bitmask)
|
||||
{
|
||||
struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
|
||||
int loops = msecs_to_loops(10);
|
||||
u32 mask = bitmask << (nr << 8);
|
||||
|
||||
@ -62,7 +65,7 @@ static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 b
|
||||
cpu_relax();
|
||||
|
||||
if (unlikely(!loops))
|
||||
dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n",
|
||||
dev_warn(pwmchip_parent(chip), "Waiting for status bits 0x%x to clear timed out\n",
|
||||
mask);
|
||||
}
|
||||
|
||||
@ -77,7 +80,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
err = clk_enable(vt8500->clk);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -103,18 +106,18 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
dc = div64_u64(c, period_ns);
|
||||
|
||||
writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_SCALAR_UPDATE);
|
||||
|
||||
writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_PERIOD_UPDATE);
|
||||
|
||||
writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_DUTY_UPDATE);
|
||||
|
||||
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
val |= CTRL_AUTOLOAD;
|
||||
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
|
||||
clk_disable(vt8500->clk);
|
||||
return 0;
|
||||
@ -128,14 +131,14 @@ static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
err = clk_enable(vt8500->clk);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "failed to enable clock\n");
|
||||
dev_err(pwmchip_parent(chip), "failed to enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
val |= CTRL_ENABLE;
|
||||
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -148,7 +151,7 @@ static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
val &= ~CTRL_ENABLE;
|
||||
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
|
||||
clk_disable(vt8500->clk);
|
||||
}
|
||||
@ -168,7 +171,7 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
|
||||
val &= ~CTRL_INVERT;
|
||||
|
||||
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
vt8500_pwm_busy_wait(chip, pwm->hwpwm, STATUS_CTRL_UPDATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -231,6 +234,7 @@ MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
|
||||
|
||||
static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct vt8500_chip *vt8500;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
@ -238,13 +242,12 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
if (!np)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "invalid devicetree node\n");
|
||||
|
||||
vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL);
|
||||
if (vt8500 == NULL)
|
||||
return -ENOMEM;
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, VT8500_NR_PWMS, sizeof(*vt8500));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
vt8500 = to_vt8500_chip(chip);
|
||||
|
||||
vt8500->chip.dev = &pdev->dev;
|
||||
vt8500->chip.ops = &vt8500_pwm_ops;
|
||||
vt8500->chip.npwm = VT8500_NR_PWMS;
|
||||
chip->ops = &vt8500_pwm_ops;
|
||||
|
||||
vt8500->clk = devm_clk_get_prepared(&pdev->dev, NULL);
|
||||
if (IS_ERR(vt8500->clk))
|
||||
@ -254,7 +257,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(vt8500->base))
|
||||
return PTR_ERR(vt8500->base);
|
||||
|
||||
ret = devm_pwmchip_add(&pdev->dev, &vt8500->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
|
@ -80,15 +80,10 @@ unsigned int xilinx_timer_get_period(struct xilinx_timer_priv *priv,
|
||||
#define TCSR_PWM_CLEAR (TCSR_MDT | TCSR_LOAD)
|
||||
#define TCSR_PWM_MASK (TCSR_PWM_SET | TCSR_PWM_CLEAR)
|
||||
|
||||
struct xilinx_pwm_device {
|
||||
struct pwm_chip chip;
|
||||
struct xilinx_timer_priv priv;
|
||||
};
|
||||
|
||||
static inline struct xilinx_timer_priv
|
||||
*xilinx_pwm_chip_to_priv(struct pwm_chip *chip)
|
||||
{
|
||||
return &container_of(chip, struct xilinx_pwm_device, chip)->priv;
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static bool xilinx_timer_pwm_enabled(u32 tcsr0, u32 tcsr1)
|
||||
@ -214,7 +209,7 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct xilinx_timer_priv *priv;
|
||||
struct xilinx_pwm_device *xilinx_pwm;
|
||||
struct pwm_chip *chip;
|
||||
u32 pwm_cells, one_timer, width;
|
||||
void __iomem *regs;
|
||||
|
||||
@ -225,11 +220,11 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "could not read #pwm-cells\n");
|
||||
|
||||
xilinx_pwm = devm_kzalloc(dev, sizeof(*xilinx_pwm), GFP_KERNEL);
|
||||
if (!xilinx_pwm)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, xilinx_pwm);
|
||||
priv = &xilinx_pwm->priv;
|
||||
chip = devm_pwmchip_alloc(dev, 1, sizeof(*priv));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
priv = xilinx_pwm_chip_to_priv(chip);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
@ -278,10 +273,8 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(dev, ret, "Clock enable failed\n");
|
||||
clk_rate_exclusive_get(priv->clk);
|
||||
|
||||
xilinx_pwm->chip.dev = dev;
|
||||
xilinx_pwm->chip.ops = &xilinx_pwm_ops;
|
||||
xilinx_pwm->chip.npwm = 1;
|
||||
ret = pwmchip_add(&xilinx_pwm->chip);
|
||||
chip->ops = &xilinx_pwm_ops;
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret) {
|
||||
clk_rate_exclusive_put(priv->clk);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
@ -293,11 +286,12 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
static void xilinx_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xilinx_pwm_device *xilinx_pwm = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip);
|
||||
|
||||
pwmchip_remove(&xilinx_pwm->chip);
|
||||
clk_rate_exclusive_put(xilinx_pwm->priv.clk);
|
||||
clk_disable_unprepare(xilinx_pwm->priv.clk);
|
||||
pwmchip_remove(chip);
|
||||
clk_rate_exclusive_put(priv->clk);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
static const struct of_device_id xilinx_pwm_of_match[] = {
|
||||
|
@ -509,10 +509,10 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
|
||||
* If device_create() fails the pwm_chip is still usable by
|
||||
* the kernel it's just not exported.
|
||||
*/
|
||||
parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
|
||||
parent = device_create(&pwm_class, pwmchip_parent(chip), MKDEV(0, 0), chip,
|
||||
"pwmchip%d", chip->id);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_warn(chip->dev,
|
||||
dev_warn(pwmchip_parent(chip),
|
||||
"device_create failed for pwm_chip sysfs export\n");
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
struct gb_pwm_chip {
|
||||
struct gb_connection *connection;
|
||||
u8 pwm_max; /* max pwm number */
|
||||
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
@ -26,32 +24,33 @@ static inline struct gb_pwm_chip *pwm_chip_to_gb_pwm_chip(struct pwm_chip *chip)
|
||||
return container_of(chip, struct gb_pwm_chip, chip);
|
||||
}
|
||||
|
||||
static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
|
||||
static int gb_pwm_get_npwm(struct gb_connection *connection)
|
||||
{
|
||||
struct gb_pwm_count_response response;
|
||||
int ret;
|
||||
|
||||
ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
|
||||
ret = gb_operation_sync(connection, GB_PWM_TYPE_PWM_COUNT,
|
||||
NULL, 0, &response, sizeof(response));
|
||||
if (ret)
|
||||
return ret;
|
||||
pwmc->pwm_max = response.count;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The request returns the highest allowed PWM id parameter. So add one
|
||||
* to get the number of PWMs.
|
||||
*/
|
||||
return response.count + 1;
|
||||
}
|
||||
|
||||
static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
|
||||
u8 which)
|
||||
static int gb_pwm_activate_operation(struct pwm_chip *chip, u8 which)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_activate_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
ret = gbphy_runtime_get_sync(gbphy_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -64,19 +63,16 @@ static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
|
||||
u8 which)
|
||||
static int gb_pwm_deactivate_operation(struct pwm_chip *chip, u8 which)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_deactivate_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
ret = gbphy_runtime_get_sync(gbphy_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -89,21 +85,19 @@ static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
|
||||
static int gb_pwm_config_operation(struct pwm_chip *chip,
|
||||
u8 which, u32 duty, u32 period)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_config_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
request.duty = cpu_to_le32(duty);
|
||||
request.period = cpu_to_le32(period);
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
ret = gbphy_runtime_get_sync(gbphy_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -116,20 +110,18 @@ static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
|
||||
static int gb_pwm_set_polarity_operation(struct pwm_chip *chip,
|
||||
u8 which, u8 polarity)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_polarity_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
request.polarity = polarity;
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
ret = gbphy_runtime_get_sync(gbphy_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -142,19 +134,16 @@ static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
|
||||
u8 which)
|
||||
static int gb_pwm_enable_operation(struct pwm_chip *chip, u8 which)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_enable_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
ret = gbphy_runtime_get_sync(gbphy_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -167,22 +156,19 @@ static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
|
||||
u8 which)
|
||||
static int gb_pwm_disable_operation(struct pwm_chip *chip, u8 which)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_pwm_disable_request request;
|
||||
struct gbphy_device *gbphy_dev;
|
||||
int ret;
|
||||
|
||||
if (which > pwmc->pwm_max)
|
||||
return -EINVAL;
|
||||
|
||||
request.which = which;
|
||||
|
||||
ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
|
||||
&request, sizeof(request), NULL, 0);
|
||||
|
||||
gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
|
||||
gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));
|
||||
gbphy_runtime_put_autosuspend(gbphy_dev);
|
||||
|
||||
return ret;
|
||||
@ -190,19 +176,15 @@ static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
|
||||
|
||||
static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
|
||||
return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
|
||||
return gb_pwm_activate_operation(chip, pwm->hwpwm);
|
||||
};
|
||||
|
||||
static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
|
||||
if (pwm_is_enabled(pwm))
|
||||
dev_warn(chip->dev, "freeing PWM device without disabling\n");
|
||||
dev_warn(pwmchip_parent(chip), "freeing PWM device without disabling\n");
|
||||
|
||||
gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
|
||||
gb_pwm_deactivate_operation(chip, pwm->hwpwm);
|
||||
}
|
||||
|
||||
static int gb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -212,22 +194,21 @@ static int gb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
bool enabled = pwm->state.enabled;
|
||||
u64 period = state->period;
|
||||
u64 duty_cycle = state->duty_cycle;
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
|
||||
/* Set polarity */
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (enabled) {
|
||||
gb_pwm_disable_operation(pwmc, pwm->hwpwm);
|
||||
gb_pwm_disable_operation(chip, pwm->hwpwm);
|
||||
enabled = false;
|
||||
}
|
||||
err = gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, state->polarity);
|
||||
err = gb_pwm_set_polarity_operation(chip, pwm->hwpwm, state->polarity);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
if (enabled)
|
||||
gb_pwm_disable_operation(pwmc, pwm->hwpwm);
|
||||
gb_pwm_disable_operation(chip, pwm->hwpwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -243,13 +224,13 @@ static int gb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (duty_cycle > period)
|
||||
duty_cycle = period;
|
||||
|
||||
err = gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_cycle, period);
|
||||
err = gb_pwm_config_operation(chip, pwm->hwpwm, duty_cycle, period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* enable/disable */
|
||||
if (!enabled)
|
||||
return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
|
||||
return gb_pwm_enable_operation(chip, pwm->hwpwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -266,61 +247,59 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
|
||||
struct gb_connection *connection;
|
||||
struct gb_pwm_chip *pwmc;
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
|
||||
if (!pwmc)
|
||||
return -ENOMEM;
|
||||
int ret, npwm;
|
||||
|
||||
connection = gb_connection_create(gbphy_dev->bundle,
|
||||
le16_to_cpu(gbphy_dev->cport_desc->id),
|
||||
NULL);
|
||||
if (IS_ERR(connection)) {
|
||||
ret = PTR_ERR(connection);
|
||||
goto exit_pwmc_free;
|
||||
}
|
||||
|
||||
pwmc->connection = connection;
|
||||
gb_connection_set_data(connection, pwmc);
|
||||
gb_gbphy_set_data(gbphy_dev, pwmc);
|
||||
if (IS_ERR(connection))
|
||||
return PTR_ERR(connection);
|
||||
|
||||
ret = gb_connection_enable(connection);
|
||||
if (ret)
|
||||
goto exit_connection_destroy;
|
||||
|
||||
/* Query number of pwms present */
|
||||
ret = gb_pwm_count_operation(pwmc);
|
||||
if (ret)
|
||||
ret = gb_pwm_get_npwm(connection);
|
||||
if (ret < 0)
|
||||
goto exit_connection_disable;
|
||||
npwm = ret;
|
||||
|
||||
chip = &pwmc->chip;
|
||||
chip = pwmchip_alloc(&gbphy_dev->dev, npwm, sizeof(*pwmc));
|
||||
if (IS_ERR(chip)) {
|
||||
ret = PTR_ERR(chip);
|
||||
goto exit_connection_disable;
|
||||
}
|
||||
gb_gbphy_set_data(gbphy_dev, chip);
|
||||
|
||||
pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
pwmc->connection = connection;
|
||||
|
||||
chip->dev = &gbphy_dev->dev;
|
||||
chip->ops = &gb_pwm_ops;
|
||||
chip->npwm = pwmc->pwm_max + 1;
|
||||
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret) {
|
||||
dev_err(&gbphy_dev->dev,
|
||||
"failed to register PWM: %d\n", ret);
|
||||
goto exit_connection_disable;
|
||||
goto exit_pwmchip_put;
|
||||
}
|
||||
|
||||
gbphy_runtime_put_autosuspend(gbphy_dev);
|
||||
return 0;
|
||||
|
||||
exit_pwmchip_put:
|
||||
pwmchip_put(chip);
|
||||
exit_connection_disable:
|
||||
gb_connection_disable(connection);
|
||||
exit_connection_destroy:
|
||||
gb_connection_destroy(connection);
|
||||
exit_pwmc_free:
|
||||
kfree(pwmc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gb_pwm_remove(struct gbphy_device *gbphy_dev)
|
||||
{
|
||||
struct gb_pwm_chip *pwmc = gb_gbphy_get_data(gbphy_dev);
|
||||
struct pwm_chip *chip = gb_gbphy_get_data(gbphy_dev);
|
||||
struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
|
||||
struct gb_connection *connection = pwmc->connection;
|
||||
int ret;
|
||||
|
||||
@ -328,10 +307,10 @@ static void gb_pwm_remove(struct gbphy_device *gbphy_dev)
|
||||
if (ret)
|
||||
gbphy_runtime_get_noresume(gbphy_dev);
|
||||
|
||||
pwmchip_remove(&pwmc->chip);
|
||||
pwmchip_remove(chip);
|
||||
pwmchip_put(chip);
|
||||
gb_connection_disable(connection);
|
||||
gb_connection_destroy(connection);
|
||||
kfree(pwmc);
|
||||
}
|
||||
|
||||
static const struct gbphy_device_id gb_pwm_id_table[] = {
|
||||
|
@ -27,7 +27,7 @@ struct pwm_lpss_boardinfo {
|
||||
bool other_devices_aml_touches_pwm_regs;
|
||||
};
|
||||
|
||||
struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
|
||||
const struct pwm_lpss_boardinfo *info);
|
||||
struct pwm_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
|
||||
const struct pwm_lpss_boardinfo *info);
|
||||
|
||||
#endif /* __PLATFORM_DATA_X86_PWM_LPSS_H */
|
||||
|
@ -271,8 +271,8 @@ struct pwm_ops {
|
||||
* @id: unique number of this PWM chip
|
||||
* @npwm: number of PWMs controlled by this chip
|
||||
* @of_xlate: request a PWM device given a device tree PWM specifier
|
||||
* @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
|
||||
* @atomic: can the driver's ->apply() be called in atomic context
|
||||
* @driver_data: Private pointer for driver specific info
|
||||
* @pwms: array of PWM devices allocated by the framework
|
||||
*/
|
||||
struct pwm_chip {
|
||||
@ -284,13 +284,36 @@ struct pwm_chip {
|
||||
|
||||
struct pwm_device * (*of_xlate)(struct pwm_chip *chip,
|
||||
const struct of_phandle_args *args);
|
||||
unsigned int of_pwm_n_cells;
|
||||
bool atomic;
|
||||
|
||||
/* only used internally by the PWM framework */
|
||||
void *driver_data;
|
||||
struct pwm_device *pwms;
|
||||
};
|
||||
|
||||
static inline struct device *pwmchip_parent(const struct pwm_chip *chip)
|
||||
{
|
||||
return chip->dev;
|
||||
}
|
||||
|
||||
static inline void *pwmchip_get_drvdata(struct pwm_chip *chip)
|
||||
{
|
||||
/*
|
||||
* After pwm_chip got a dedicated struct device, this can be replaced by
|
||||
* dev_get_drvdata(&chip->dev);
|
||||
*/
|
||||
return chip->driver_data;
|
||||
}
|
||||
|
||||
static inline void pwmchip_set_drvdata(struct pwm_chip *chip, void *data)
|
||||
{
|
||||
/*
|
||||
* After pwm_chip got a dedicated struct device, this can be replaced by
|
||||
* dev_set_drvdata(&chip->dev, data);
|
||||
*/
|
||||
chip->driver_data = data;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_PWM)
|
||||
/* PWM user APIs */
|
||||
int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state);
|
||||
@ -380,6 +403,10 @@ static inline bool pwm_might_sleep(struct pwm_device *pwm)
|
||||
int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
|
||||
unsigned long timeout);
|
||||
|
||||
void pwmchip_put(struct pwm_chip *chip);
|
||||
struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
|
||||
struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
|
||||
|
||||
int __pwmchip_add(struct pwm_chip *chip, struct module *owner);
|
||||
#define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE)
|
||||
void pwmchip_remove(struct pwm_chip *chip);
|
||||
@ -452,6 +479,24 @@ static inline int pwm_capture(struct pwm_device *pwm,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void pwmchip_put(struct pwm_chip *chip)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct pwm_chip *pwmchip_alloc(struct device *parent,
|
||||
unsigned int npwm,
|
||||
size_t sizeof_priv)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline struct pwm_chip *devm_pwmchip_alloc(struct device *parent,
|
||||
unsigned int npwm,
|
||||
size_t sizeof_priv)
|
||||
{
|
||||
return pwmchip_alloc(parent, npwm, sizeof_priv);
|
||||
}
|
||||
|
||||
static inline int pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
Loading…
Reference in New Issue
Block a user