pwm: Changes for v5.14-rc1
This contains mostly various fixes, cleanups and some conversions to the atomic API. One noteworthy change is that PWM consumers can now pass a hint to the PWM core about the PWM usage, enabling PWM providers to implement various optimizations. There's also a fair bit of simplification here with the addition of some device-managed helpers as well as unification between the DT and ACPI firmware interfaces. -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmDm1xQZHHRoaWVycnku cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zoWFAD/91RO2EJTnzdi267AfFtToV icMYZxOj0XN3AZ4WTbFkfeTPxCd3Kdg777gc5/NfzJM0nln/aWTf7qHAvMRZsesI HNQkRq7gXCMh5QPk44bvYhWseUQqZ3cpW6H878K7ocCox3YpMjeElPdxXTHd3Lth pUTE5mVJxw9alxva7p+gvRKvj9YLucQ3NFLjAL8lCUFzLFP0ZZc2O6BoBSQJDCS5 UN2hfgFfsYlrXxFVJLn/KsrZcF8TNUcRgLNQZ5j/D0snTSaF2QMdQL7UWZbTvOkf EEOpS2e1kZJNXA61YcR+AoQrx/ZITjhfkZ65oyWBNummfk3QniuwvMYon/0SPoLV 6KeyeRTTAL012JeH4AxVC9yuljki+PRnYHrn+wD4CUiBA5dc4+KY+eOJ/FOiroZV V4yi7YvUrQuasazN8ucFg4ukGgtctkEyEUskfvkNDOOLAtxn814tn9zuplP0WTw9 LNg4rxalUS4fxBR13q0RszCb2I03I1sK2Wkia1HcUS/U4qa0fj59zJw0UtFhDVkp /sRLLYHb54lIi4jhgdnbSPrhQxJA5B8HD5gX7JVc4ABk/1piWxXIE2sdsvauKqWX VCDGAxIkDB0QTcfZ35gHALlG4VqFibJEspaR4abUQKA3cE9aocX5XjRflnEUivVM EgUI6zqDRq1PnPnGUblqpA== =Hns1 -----END PGP SIGNATURE----- Merge tag 'pwm/for-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm Pull pwm updates from Thierry Reding: "This contains mostly various fixes, cleanups and some conversions to the atomic API. One noteworthy change is that PWM consumers can now pass a hint to the PWM core about the PWM usage, enabling PWM providers to implement various optimizations. There's also a fair bit of simplification here with the addition of some device-managed helpers as well as unification between the DT and ACPI firmware interfaces" * tag 'pwm/for-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (50 commits) pwm: Remove redundant assignment to pointer pwm pwm: ep93xx: Fix read of uninitialized variable ret pwm: ep93xx: Prepare clock before using it pwm: ep93xx: Unfold legacy callbacks into ep93xx_pwm_apply() pwm: ep93xx: Implement .apply callback pwm: vt8500: Only unprepare the clock after the pwmchip was removed pwm: vt8500: Drop if with an always false condition pwm: tegra: Assert reset only after the PWM was unregistered pwm: tegra: Don't needlessly enable and disable the clock in .remove() pwm: tegra: Don't modify HW state in .remove callback pwm: tegra: Drop an if block with an always false condition pwm: core: Simplify some devm_*pwm*() functions pwm: core: Remove unused devm_pwm_put() pwm: core: Unify fwnode checks in the module pwm: core: Reuse fwnode_to_pwmchip() in ACPI case pwm: core: Convert to use fwnode for matching docs: firmware-guide: ACPI: Add a PWM example dt-bindings: pwm: pwm-tiecap: Add compatible string for AM64 SoC dt-bindings: pwm: pwm-tiecap: Convert to json schema pwm: sprd: Don't check the return code of pwmchip_remove() ...
This commit is contained in:
Коммит
8c1bfd7460
|
@ -1,51 +0,0 @@
|
||||||
TI SOC ECAP based APWM controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Must be "ti,<soc>-ecap".
|
|
||||||
for am33xx - compatible = "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
for am4372 - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
|
|
||||||
for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
|
|
||||||
for am654 - compatible = "ti,am654-ecap", "ti,am3352-ecap";
|
|
||||||
- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
|
|
||||||
the cells format. The PWM channel index ranges from 0 to 4. The only third
|
|
||||||
cell flag supported by this binding is PWM_POLARITY_INVERTED.
|
|
||||||
- reg: physical base address and size of the registers map.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- clocks: Handle to the ECAP's functional clock.
|
|
||||||
- clock-names: Must be set to "fck".
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
ecap0: ecap@48300100 { /* ECAP on am33xx */
|
|
||||||
compatible = "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x48300100 0x80>;
|
|
||||||
clocks = <&l4ls_gclk>;
|
|
||||||
clock-names = "fck";
|
|
||||||
};
|
|
||||||
|
|
||||||
ecap0: ecap@48300100 { /* ECAP on am4372 */
|
|
||||||
compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x48300100 0x80>;
|
|
||||||
ti,hwmods = "ecap0";
|
|
||||||
clocks = <&l4ls_gclk>;
|
|
||||||
clock-names = "fck";
|
|
||||||
};
|
|
||||||
|
|
||||||
ecap0: ecap@1f06000 { /* ECAP on da850 */
|
|
||||||
compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x1f06000 0x80>;
|
|
||||||
};
|
|
||||||
|
|
||||||
ecap0: ecap@4843e100 {
|
|
||||||
compatible = "ti,dra746-ecap", "ti,am3352-ecap";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x4843e100 0x80>;
|
|
||||||
clocks = <&l4_root_clk_div>;
|
|
||||||
clock-names = "fck";
|
|
||||||
};
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/pwm/pwm-tiecap.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: TI SOC ECAP based APWM controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Vignesh R <vigneshr@ti.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: pwm.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- const: ti,am3352-ecap
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- ti,da850-ecap
|
||||||
|
- ti,am4372-ecap
|
||||||
|
- ti,dra746-ecap
|
||||||
|
- ti,k2g-ecap
|
||||||
|
- ti,am654-ecap
|
||||||
|
- ti,am64-ecap
|
||||||
|
- const: ti,am3352-ecap
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#pwm-cells":
|
||||||
|
const: 3
|
||||||
|
description: |
|
||||||
|
See pwm.yaml in this directory for a description of the cells format.
|
||||||
|
The only third cell flag supported by this binding is PWM_POLARITY_INVERTED.
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: fck
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#pwm-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
ecap0: pwm@48300100 { /* ECAP on am33xx */
|
||||||
|
compatible = "ti,am3352-ecap";
|
||||||
|
#pwm-cells = <3>;
|
||||||
|
reg = <0x48300100 0x80>;
|
||||||
|
clocks = <&l4ls_gclk>;
|
||||||
|
clock-names = "fck";
|
||||||
|
};
|
|
@ -1,50 +0,0 @@
|
||||||
TI SOC EHRPWM based PWM controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Must be "ti,<soc>-ehrpwm".
|
|
||||||
for am33xx - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
for am4372 - compatible = "ti,am4372-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
for am654 - compatible = "ti,am654-ehrpwm", "ti-am3352-ehrpwm";
|
|
||||||
for da850 - compatible = "ti,da850-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
for dra746 - compatible = "ti,dra746-ehrpwm", "ti-am3352-ehrpwm";
|
|
||||||
- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of
|
|
||||||
the cells format. The only third cell flag supported by this binding is
|
|
||||||
PWM_POLARITY_INVERTED.
|
|
||||||
- reg: physical base address and size of the registers map.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- clocks: Handle to the PWM's time-base and functional clock.
|
|
||||||
- clock-names: Must be set to "tbclk" and "fck".
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
ehrpwm0: pwm@48300200 { /* EHRPWM on am33xx */
|
|
||||||
compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x48300200 0x100>;
|
|
||||||
clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>;
|
|
||||||
clock-names = "tbclk", "fck";
|
|
||||||
};
|
|
||||||
|
|
||||||
ehrpwm0: pwm@48300200 { /* EHRPWM on am4372 */
|
|
||||||
compatible = "ti,am4372-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x48300200 0x80>;
|
|
||||||
clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>;
|
|
||||||
clock-names = "tbclk", "fck";
|
|
||||||
ti,hwmods = "ehrpwm0";
|
|
||||||
};
|
|
||||||
|
|
||||||
ehrpwm0: pwm@1f00000 { /* EHRPWM on da850 */
|
|
||||||
compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x1f00000 0x2000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
ehrpwm0: pwm@4843e200 { /* EHRPWM on dra746 */
|
|
||||||
compatible = "ti,dra746-ehrpwm", "ti,am3352-ehrpwm";
|
|
||||||
#pwm-cells = <3>;
|
|
||||||
reg = <0x4843e200 0x80>;
|
|
||||||
clocks = <&ehrpwm0_tbclk>, <&l4_root_clk_div>;
|
|
||||||
clock-names = "tbclk", "fck";
|
|
||||||
};
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/pwm/pwm-tiehrpwm.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: TI SOC EHRPWM based PWM controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Vignesh R <vigneshr@ti.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: pwm.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- const: ti,am3352-ehrpwm
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- ti,da850-ehrpwm
|
||||||
|
- ti,am4372-ehrpwm
|
||||||
|
- ti,dra746-ehrpwm
|
||||||
|
- ti,am654-ehrpwm
|
||||||
|
- ti,am64-epwm
|
||||||
|
- const: ti,am3352-ehrpwm
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#pwm-cells":
|
||||||
|
const: 3
|
||||||
|
description: |
|
||||||
|
See pwm.yaml in this directory for a description of the cells format.
|
||||||
|
The only third cell flag supported by this binding is PWM_POLARITY_INVERTED.
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: tbclk
|
||||||
|
- const: fck
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 2
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#pwm-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
ehrpwm0: pwm@48300200 { /* EHRPWM on am33xx */
|
||||||
|
compatible = "ti,am3352-ehrpwm";
|
||||||
|
#pwm-cells = <3>;
|
||||||
|
reg = <0x48300200 0x100>;
|
||||||
|
clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>;
|
||||||
|
clock-names = "tbclk", "fck";
|
||||||
|
};
|
|
@ -400,7 +400,8 @@ POWER
|
||||||
|
|
||||||
PWM
|
PWM
|
||||||
devm_pwm_get()
|
devm_pwm_get()
|
||||||
devm_pwm_put()
|
devm_of_pwm_get()
|
||||||
|
devm_fwnode_pwm_get()
|
||||||
|
|
||||||
REGULATOR
|
REGULATOR
|
||||||
devm_regulator_bulk_get()
|
devm_regulator_bulk_get()
|
||||||
|
|
|
@ -40,7 +40,8 @@ after usage with pwm_free().
|
||||||
|
|
||||||
New users should use the pwm_get() function and pass to it the consumer
|
New users should use the pwm_get() function and pass to it the consumer
|
||||||
device or a consumer name. pwm_put() is used to free the PWM device. Managed
|
device or a consumer name. pwm_put() is used to free the PWM device. Managed
|
||||||
variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
|
variants of the getter, devm_pwm_get(), devm_of_pwm_get(),
|
||||||
|
devm_fwnode_pwm_get(), also exist.
|
||||||
|
|
||||||
After being requested, a PWM has to be configured using::
|
After being requested, a PWM has to be configured using::
|
||||||
|
|
||||||
|
@ -48,6 +49,10 @@ After being requested, a PWM has to be configured using::
|
||||||
|
|
||||||
This API controls both the PWM period/duty_cycle config and the
|
This API controls both the PWM period/duty_cycle config and the
|
||||||
enable/disable state.
|
enable/disable state.
|
||||||
|
There is also a usage_power setting: If set, the PWM driver is only required to
|
||||||
|
maintain the power output but has more freedom regarding signal form.
|
||||||
|
If supported by the driver, the signal can be optimized, for example to improve
|
||||||
|
EMI by phase shifting the individual channels of a chip.
|
||||||
|
|
||||||
The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers
|
The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers
|
||||||
around pwm_apply_state() and should not be used if the user wants to change
|
around pwm_apply_state() and should not be used if the user wants to change
|
||||||
|
|
|
@ -258,6 +258,38 @@ input driver::
|
||||||
.id_table = mpu3050_ids,
|
.id_table = mpu3050_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference to PWM device
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Sometimes a device can be a consumer of PWM channel. Obviously OS would like
|
||||||
|
to know which one. To provide this mapping the special property has been
|
||||||
|
introduced, i.e.::
|
||||||
|
|
||||||
|
Device (DEV)
|
||||||
|
{
|
||||||
|
Name (_DSD, Package ()
|
||||||
|
{
|
||||||
|
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
|
||||||
|
Package () {
|
||||||
|
Package () { "compatible", Package () { "pwm-leds" } },
|
||||||
|
Package () { "label", "alarm-led" },
|
||||||
|
Package () { "pwms",
|
||||||
|
Package () {
|
||||||
|
"\\_SB.PCI0.PWM", // <PWM device reference>
|
||||||
|
0, // <PWM index>
|
||||||
|
600000000, // <PWM period>
|
||||||
|
0, // <PWM flags>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
...
|
||||||
|
|
||||||
|
In the above example the PWM-based LED driver references to the PWM channel 0
|
||||||
|
of \_SB.PCI0.PWM device with initial period setting equal to 600 ms (note that
|
||||||
|
value is given in nanoseconds).
|
||||||
|
|
||||||
GPIO support
|
GPIO support
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
|
@ -126,8 +126,7 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||||
{
|
{
|
||||||
struct pwm_device *pwm;
|
struct pwm_device *pwm;
|
||||||
|
|
||||||
/* check, whether the driver supports a third cell for flags */
|
if (pc->of_pwm_n_cells < 2)
|
||||||
if (pc->of_pwm_n_cells < 3)
|
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
/* flags in the third cell are optional */
|
/* flags in the third cell are optional */
|
||||||
|
@ -144,46 +143,29 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||||
pwm->args.period = args->args[1];
|
pwm->args.period = args->args[1];
|
||||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||||
|
|
||||||
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
if (pc->of_pwm_n_cells >= 3) {
|
||||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
||||||
|
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||||
|
}
|
||||||
|
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
|
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
|
||||||
|
|
||||||
static struct pwm_device *
|
|
||||||
of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
|
|
||||||
{
|
|
||||||
struct pwm_device *pwm;
|
|
||||||
|
|
||||||
/* sanity check driver support */
|
|
||||||
if (pc->of_pwm_n_cells < 2)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
/* all cells are required */
|
|
||||||
if (args->args_count != pc->of_pwm_n_cells)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
if (args->args[0] >= pc->npwm)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
|
|
||||||
if (IS_ERR(pwm))
|
|
||||||
return pwm;
|
|
||||||
|
|
||||||
pwm->args.period = args->args[1];
|
|
||||||
|
|
||||||
return pwm;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void of_pwmchip_add(struct pwm_chip *chip)
|
static void of_pwmchip_add(struct pwm_chip *chip)
|
||||||
{
|
{
|
||||||
if (!chip->dev || !chip->dev->of_node)
|
if (!chip->dev || !chip->dev->of_node)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!chip->of_xlate) {
|
if (!chip->of_xlate) {
|
||||||
chip->of_xlate = of_pwm_simple_xlate;
|
u32 pwm_cells;
|
||||||
chip->of_pwm_n_cells = 2;
|
|
||||||
|
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);
|
of_node_get(chip->dev->of_node);
|
||||||
|
@ -324,22 +306,10 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
|
||||||
*/
|
*/
|
||||||
int pwmchip_remove(struct pwm_chip *chip)
|
int pwmchip_remove(struct pwm_chip *chip)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
pwmchip_sysfs_unexport(chip);
|
pwmchip_sysfs_unexport(chip);
|
||||||
|
|
||||||
mutex_lock(&pwm_lock);
|
mutex_lock(&pwm_lock);
|
||||||
|
|
||||||
for (i = 0; i < chip->npwm; i++) {
|
|
||||||
struct pwm_device *pwm = &chip->pwms[i];
|
|
||||||
|
|
||||||
if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del_init(&chip->list);
|
list_del_init(&chip->list);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_OF))
|
if (IS_ENABLED(CONFIG_OF))
|
||||||
|
@ -347,12 +317,31 @@ int pwmchip_remove(struct pwm_chip *chip)
|
||||||
|
|
||||||
free_pwms(chip);
|
free_pwms(chip);
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&pwm_lock);
|
mutex_unlock(&pwm_lock);
|
||||||
return ret;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pwmchip_remove);
|
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)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pwmchip_add(chip);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_pwmchip_add);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pwm_request() - request a PWM device
|
* pwm_request() - request a PWM device
|
||||||
* @pwm: global PWM device index
|
* @pwm: global PWM device index
|
||||||
|
@ -554,7 +543,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
|
||||||
if (state->period == pwm->state.period &&
|
if (state->period == pwm->state.period &&
|
||||||
state->duty_cycle == pwm->state.duty_cycle &&
|
state->duty_cycle == pwm->state.duty_cycle &&
|
||||||
state->polarity == pwm->state.polarity &&
|
state->polarity == pwm->state.polarity &&
|
||||||
state->enabled == pwm->state.enabled)
|
state->enabled == pwm->state.enabled &&
|
||||||
|
state->usage_power == pwm->state.usage_power)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (chip->ops->apply) {
|
if (chip->ops->apply) {
|
||||||
|
@ -709,14 +699,14 @@ int pwm_adjust_config(struct pwm_device *pwm)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pwm_adjust_config);
|
EXPORT_SYMBOL_GPL(pwm_adjust_config);
|
||||||
|
|
||||||
static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
|
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct pwm_chip *chip;
|
struct pwm_chip *chip;
|
||||||
|
|
||||||
mutex_lock(&pwm_lock);
|
mutex_lock(&pwm_lock);
|
||||||
|
|
||||||
list_for_each_entry(chip, &pwm_chips, list)
|
list_for_each_entry(chip, &pwm_chips, list)
|
||||||
if (chip->dev && chip->dev->of_node == np) {
|
if (chip->dev && dev_fwnode(chip->dev) == fwnode) {
|
||||||
mutex_unlock(&pwm_lock);
|
mutex_unlock(&pwm_lock);
|
||||||
return chip;
|
return chip;
|
||||||
}
|
}
|
||||||
|
@ -795,7 +785,7 @@ struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
pc = of_node_to_pwmchip(args.np);
|
pc = fwnode_to_pwmchip(of_fwnode_handle(args.np));
|
||||||
if (IS_ERR(pc)) {
|
if (IS_ERR(pc)) {
|
||||||
if (PTR_ERR(pc) != -EPROBE_DEFER)
|
if (PTR_ERR(pc) != -EPROBE_DEFER)
|
||||||
pr_err("%s(): PWM chip not found\n", __func__);
|
pr_err("%s(): PWM chip not found\n", __func__);
|
||||||
|
@ -837,31 +827,9 @@ put:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_pwm_get);
|
EXPORT_SYMBOL_GPL(of_pwm_get);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ACPI)
|
|
||||||
static struct pwm_chip *device_to_pwmchip(struct device *dev)
|
|
||||||
{
|
|
||||||
struct pwm_chip *chip;
|
|
||||||
|
|
||||||
mutex_lock(&pwm_lock);
|
|
||||||
|
|
||||||
list_for_each_entry(chip, &pwm_chips, list) {
|
|
||||||
struct acpi_device *adev = ACPI_COMPANION(chip->dev);
|
|
||||||
|
|
||||||
if ((chip->dev == dev) || (adev && &adev->dev == dev)) {
|
|
||||||
mutex_unlock(&pwm_lock);
|
|
||||||
return chip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&pwm_lock);
|
|
||||||
|
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI
|
* acpi_pwm_get() - request a PWM via parsing "pwms" property in ACPI
|
||||||
* @fwnode: firmware node to get the "pwm" property from
|
* @fwnode: firmware node to get the "pwms" property from
|
||||||
*
|
*
|
||||||
* Returns the PWM device parsed from the fwnode and index specified in the
|
* Returns the PWM device parsed from the fwnode and index specified in the
|
||||||
* "pwms" property or a negative error-code on failure.
|
* "pwms" property or a negative error-code on failure.
|
||||||
|
@ -876,12 +844,10 @@ static struct pwm_chip *device_to_pwmchip(struct device *dev)
|
||||||
* Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
|
* Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded
|
||||||
* error code on failure.
|
* error code on failure.
|
||||||
*/
|
*/
|
||||||
static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
|
static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct pwm_device *pwm = ERR_PTR(-ENODEV);
|
struct pwm_device *pwm;
|
||||||
#if IS_ENABLED(CONFIG_ACPI)
|
|
||||||
struct fwnode_reference_args args;
|
struct fwnode_reference_args args;
|
||||||
struct acpi_device *acpi;
|
|
||||||
struct pwm_chip *chip;
|
struct pwm_chip *chip;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -891,14 +857,10 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
acpi = to_acpi_device_node(args.fwnode);
|
|
||||||
if (!acpi)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
if (args.nargs < 2)
|
if (args.nargs < 2)
|
||||||
return ERR_PTR(-EPROTO);
|
return ERR_PTR(-EPROTO);
|
||||||
|
|
||||||
chip = device_to_pwmchip(&acpi->dev);
|
chip = fwnode_to_pwmchip(args.fwnode);
|
||||||
if (IS_ERR(chip))
|
if (IS_ERR(chip))
|
||||||
return ERR_CAST(chip);
|
return ERR_CAST(chip);
|
||||||
|
|
||||||
|
@ -911,7 +873,6 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
|
||||||
|
|
||||||
if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED)
|
if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED)
|
||||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||||
#endif
|
|
||||||
|
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
|
@ -967,6 +928,7 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
|
||||||
*/
|
*/
|
||||||
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
||||||
{
|
{
|
||||||
|
const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
|
||||||
const char *dev_id = dev ? dev_name(dev) : NULL;
|
const char *dev_id = dev ? dev_name(dev) : NULL;
|
||||||
struct pwm_device *pwm;
|
struct pwm_device *pwm;
|
||||||
struct pwm_chip *chip;
|
struct pwm_chip *chip;
|
||||||
|
@ -977,12 +939,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* look up via DT first */
|
/* look up via DT first */
|
||||||
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
|
if (is_of_node(fwnode))
|
||||||
return of_pwm_get(dev, dev->of_node, con_id);
|
return of_pwm_get(dev, to_of_node(fwnode), con_id);
|
||||||
|
|
||||||
/* then lookup via ACPI */
|
/* then lookup via ACPI */
|
||||||
if (dev && is_acpi_node(dev->fwnode)) {
|
if (is_acpi_node(fwnode)) {
|
||||||
pwm = acpi_pwm_get(dev->fwnode);
|
pwm = acpi_pwm_get(fwnode);
|
||||||
if (!IS_ERR(pwm) || PTR_ERR(pwm) != -ENOENT)
|
if (!IS_ERR(pwm) || PTR_ERR(pwm) != -ENOENT)
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
|
@ -1103,9 +1065,9 @@ out:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pwm_put);
|
EXPORT_SYMBOL_GPL(pwm_put);
|
||||||
|
|
||||||
static void devm_pwm_release(struct device *dev, void *res)
|
static void devm_pwm_release(void *pwm)
|
||||||
{
|
{
|
||||||
pwm_put(*(struct pwm_device **)res);
|
pwm_put(pwm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1121,19 +1083,16 @@ static void devm_pwm_release(struct device *dev, void *res)
|
||||||
*/
|
*/
|
||||||
struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
|
struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
|
||||||
{
|
{
|
||||||
struct pwm_device **ptr, *pwm;
|
struct pwm_device *pwm;
|
||||||
|
int ret;
|
||||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
|
||||||
if (!ptr)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
pwm = pwm_get(dev, con_id);
|
pwm = pwm_get(dev, con_id);
|
||||||
if (!IS_ERR(pwm)) {
|
if (IS_ERR(pwm))
|
||||||
*ptr = pwm;
|
return pwm;
|
||||||
devres_add(dev, ptr);
|
|
||||||
} else {
|
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||||
devres_free(ptr);
|
if (ret)
|
||||||
}
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
|
@ -1154,19 +1113,16 @@ EXPORT_SYMBOL_GPL(devm_pwm_get);
|
||||||
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
|
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
|
||||||
const char *con_id)
|
const char *con_id)
|
||||||
{
|
{
|
||||||
struct pwm_device **ptr, *pwm;
|
struct pwm_device *pwm;
|
||||||
|
int ret;
|
||||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
|
||||||
if (!ptr)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
pwm = of_pwm_get(dev, np, con_id);
|
pwm = of_pwm_get(dev, np, con_id);
|
||||||
if (!IS_ERR(pwm)) {
|
if (IS_ERR(pwm))
|
||||||
*ptr = pwm;
|
return pwm;
|
||||||
devres_add(dev, ptr);
|
|
||||||
} else {
|
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||||
devres_free(ptr);
|
if (ret)
|
||||||
}
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
|
@ -1188,53 +1144,24 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
|
||||||
struct fwnode_handle *fwnode,
|
struct fwnode_handle *fwnode,
|
||||||
const char *con_id)
|
const char *con_id)
|
||||||
{
|
{
|
||||||
struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV);
|
struct pwm_device *pwm = ERR_PTR(-ENODEV);
|
||||||
|
int ret;
|
||||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
|
||||||
if (!ptr)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
if (is_of_node(fwnode))
|
if (is_of_node(fwnode))
|
||||||
pwm = of_pwm_get(dev, to_of_node(fwnode), con_id);
|
pwm = of_pwm_get(dev, to_of_node(fwnode), con_id);
|
||||||
else if (is_acpi_node(fwnode))
|
else if (is_acpi_node(fwnode))
|
||||||
pwm = acpi_pwm_get(fwnode);
|
pwm = acpi_pwm_get(fwnode);
|
||||||
|
if (IS_ERR(pwm))
|
||||||
|
return pwm;
|
||||||
|
|
||||||
if (!IS_ERR(pwm)) {
|
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||||
*ptr = pwm;
|
if (ret)
|
||||||
devres_add(dev, ptr);
|
return ERR_PTR(ret);
|
||||||
} else {
|
|
||||||
devres_free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pwm;
|
return pwm;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get);
|
EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get);
|
||||||
|
|
||||||
static int devm_pwm_match(struct device *dev, void *res, void *data)
|
|
||||||
{
|
|
||||||
struct pwm_device **p = res;
|
|
||||||
|
|
||||||
if (WARN_ON(!p || !*p))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return *p == data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* devm_pwm_put() - resource managed pwm_put()
|
|
||||||
* @dev: device for PWM consumer
|
|
||||||
* @pwm: PWM device
|
|
||||||
*
|
|
||||||
* Release a PWM previously allocated using devm_pwm_get(). Calling this
|
|
||||||
* function is usually not needed because devm-allocated resources are
|
|
||||||
* automatically released on driver detach.
|
|
||||||
*/
|
|
||||||
void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
|
|
||||||
{
|
|
||||||
WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm));
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(devm_pwm_put);
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
|
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
|
||||||
{
|
{
|
||||||
|
@ -1259,6 +1186,9 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
|
||||||
seq_printf(s, " polarity: %s",
|
seq_printf(s, " polarity: %s",
|
||||||
state.polarity ? "inverse" : "normal");
|
state.polarity ? "inverse" : "normal");
|
||||||
|
|
||||||
|
if (state.usage_power)
|
||||||
|
seq_puts(s, " usage_power");
|
||||||
|
|
||||||
seq_puts(s, "\n");
|
seq_puts(s, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,8 +266,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
|
||||||
chip->chip.ops = &atmel_hlcdc_pwm_ops;
|
chip->chip.ops = &atmel_hlcdc_pwm_ops;
|
||||||
chip->chip.dev = dev;
|
chip->chip.dev = dev;
|
||||||
chip->chip.npwm = 1;
|
chip->chip.npwm = 1;
|
||||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
chip->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
ret = pwmchip_add(&chip->chip);
|
ret = pwmchip_add(&chip->chip);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -469,8 +469,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
tcbpwm->chip.dev = &pdev->dev;
|
tcbpwm->chip.dev = &pdev->dev;
|
||||||
tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
|
tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
|
||||||
tcbpwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
tcbpwm->chip.of_pwm_n_cells = 3;
|
|
||||||
tcbpwm->chip.npwm = NPWM;
|
tcbpwm->chip.npwm = NPWM;
|
||||||
tcbpwm->channel = channel;
|
tcbpwm->channel = channel;
|
||||||
tcbpwm->regmap = regmap;
|
tcbpwm->regmap = regmap;
|
||||||
|
|
|
@ -436,8 +436,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
atmel_pwm->chip.dev = &pdev->dev;
|
atmel_pwm->chip.dev = &pdev->dev;
|
||||||
atmel_pwm->chip.ops = &atmel_pwm_ops;
|
atmel_pwm->chip.ops = &atmel_pwm_ops;
|
||||||
atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
atmel_pwm->chip.of_pwm_n_cells = 3;
|
|
||||||
atmel_pwm->chip.npwm = 4;
|
atmel_pwm->chip.npwm = 4;
|
||||||
|
|
||||||
ret = pwmchip_add(&atmel_pwm->chip);
|
ret = pwmchip_add(&atmel_pwm->chip);
|
||||||
|
|
|
@ -210,8 +210,6 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||||
ip->chip.dev = &pdev->dev;
|
ip->chip.dev = &pdev->dev;
|
||||||
ip->chip.ops = &iproc_pwm_ops;
|
ip->chip.ops = &iproc_pwm_ops;
|
||||||
ip->chip.npwm = 4;
|
ip->chip.npwm = 4;
|
||||||
ip->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
ip->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
ip->base = devm_platform_ioremap_resource(pdev, 0);
|
ip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(ip->base))
|
if (IS_ERR(ip->base))
|
||||||
|
|
|
@ -272,8 +272,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
|
||||||
kp->chip.dev = &pdev->dev;
|
kp->chip.dev = &pdev->dev;
|
||||||
kp->chip.ops = &kona_pwm_ops;
|
kp->chip.ops = &kona_pwm_ops;
|
||||||
kp->chip.npwm = 6;
|
kp->chip.npwm = 6;
|
||||||
kp->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
kp->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
kp->base = devm_platform_ioremap_resource(pdev, 0);
|
kp->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(kp->base))
|
if (IS_ERR(kp->base))
|
||||||
|
|
|
@ -159,8 +159,6 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
|
||||||
pc->chip.dev = &pdev->dev;
|
pc->chip.dev = &pdev->dev;
|
||||||
pc->chip.ops = &bcm2835_pwm_ops;
|
pc->chip.ops = &bcm2835_pwm_ops;
|
||||||
pc->chip.npwm = 2;
|
pc->chip.npwm = 2;
|
||||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pc->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pc);
|
platform_set_drvdata(pdev, pc);
|
||||||
|
|
||||||
|
|
|
@ -56,17 +56,17 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
|
||||||
return container_of(chip, struct berlin_pwm_chip, chip);
|
return container_of(chip, struct berlin_pwm_chip, chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
|
static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *bpc,
|
||||||
unsigned int channel, unsigned long offset)
|
unsigned int channel, unsigned long offset)
|
||||||
{
|
{
|
||||||
return readl_relaxed(chip->base + channel * 0x10 + offset);
|
return readl_relaxed(bpc->base + channel * 0x10 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip,
|
static inline void berlin_pwm_writel(struct berlin_pwm_chip *bpc,
|
||||||
unsigned int channel, u32 value,
|
unsigned int channel, u32 value,
|
||||||
unsigned long offset)
|
unsigned long offset)
|
||||||
{
|
{
|
||||||
writel_relaxed(value, chip->base + channel * 0x10 + offset);
|
writel_relaxed(value, bpc->base + channel * 0x10 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
|
@ -87,15 +87,15 @@ static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
kfree(channel);
|
kfree(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
int duty_ns, int period_ns)
|
u64 duty_ns, u64 period_ns)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
|
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||||
bool prescale_4096 = false;
|
bool prescale_4096 = false;
|
||||||
u32 value, duty, period;
|
u32 value, duty, period;
|
||||||
u64 cycles;
|
u64 cycles;
|
||||||
|
|
||||||
cycles = clk_get_rate(pwm->clk);
|
cycles = clk_get_rate(bpc->clk);
|
||||||
cycles *= period_ns;
|
cycles *= period_ns;
|
||||||
do_div(cycles, NSEC_PER_SEC);
|
do_div(cycles, NSEC_PER_SEC);
|
||||||
|
|
||||||
|
@ -112,68 +112,101 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
||||||
do_div(cycles, period_ns);
|
do_div(cycles, period_ns);
|
||||||
duty = cycles;
|
duty = cycles;
|
||||||
|
|
||||||
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
|
value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL);
|
||||||
if (prescale_4096)
|
if (prescale_4096)
|
||||||
value |= BERLIN_PWM_PRESCALE_4096;
|
value |= BERLIN_PWM_PRESCALE_4096;
|
||||||
else
|
else
|
||||||
value &= ~BERLIN_PWM_PRESCALE_4096;
|
value &= ~BERLIN_PWM_PRESCALE_4096;
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
|
berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL);
|
||||||
|
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
|
berlin_pwm_writel(bpc, pwm->hwpwm, duty, BERLIN_PWM_DUTY);
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT);
|
berlin_pwm_writel(bpc, pwm->hwpwm, period, BERLIN_PWM_TCNT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_set_polarity(struct pwm_chip *chip,
|
static int berlin_pwm_set_polarity(struct pwm_chip *chip,
|
||||||
struct pwm_device *pwm_dev,
|
struct pwm_device *pwm,
|
||||||
enum pwm_polarity polarity)
|
enum pwm_polarity polarity)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
|
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
|
value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL);
|
||||||
|
|
||||||
if (polarity == PWM_POLARITY_NORMAL)
|
if (polarity == PWM_POLARITY_NORMAL)
|
||||||
value &= ~BERLIN_PWM_INVERT_POLARITY;
|
value &= ~BERLIN_PWM_INVERT_POLARITY;
|
||||||
else
|
else
|
||||||
value |= BERLIN_PWM_INVERT_POLARITY;
|
value |= BERLIN_PWM_INVERT_POLARITY;
|
||||||
|
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
|
berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
|
static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
|
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
|
value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN);
|
||||||
value |= BERLIN_PWM_ENABLE;
|
value |= BERLIN_PWM_ENABLE;
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
|
berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void berlin_pwm_disable(struct pwm_chip *chip,
|
static void berlin_pwm_disable(struct pwm_chip *chip,
|
||||||
struct pwm_device *pwm_dev)
|
struct pwm_device *pwm)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
|
struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
|
value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN);
|
||||||
value &= ~BERLIN_PWM_ENABLE;
|
value &= ~BERLIN_PWM_ENABLE;
|
||||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
|
berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int berlin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
const struct pwm_state *state)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
bool enabled = pwm->state.enabled;
|
||||||
|
|
||||||
|
if (state->polarity != pwm->state.polarity) {
|
||||||
|
if (enabled) {
|
||||||
|
berlin_pwm_disable(chip, pwm);
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = berlin_pwm_set_polarity(chip, pwm, state->polarity);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state->enabled) {
|
||||||
|
if (enabled)
|
||||||
|
berlin_pwm_disable(chip, pwm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->period != pwm->state.period ||
|
||||||
|
state->duty_cycle != pwm->state.duty_cycle) {
|
||||||
|
err = berlin_pwm_config(chip, pwm, state->duty_cycle, state->period);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return berlin_pwm_enable(chip, pwm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pwm_ops berlin_pwm_ops = {
|
static const struct pwm_ops berlin_pwm_ops = {
|
||||||
.request = berlin_pwm_request,
|
.request = berlin_pwm_request,
|
||||||
.free = berlin_pwm_free,
|
.free = berlin_pwm_free,
|
||||||
.config = berlin_pwm_config,
|
.apply = berlin_pwm_apply,
|
||||||
.set_polarity = berlin_pwm_set_polarity,
|
|
||||||
.enable = berlin_pwm_enable,
|
|
||||||
.disable = berlin_pwm_disable,
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,99 +218,97 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match);
|
||||||
|
|
||||||
static int berlin_pwm_probe(struct platform_device *pdev)
|
static int berlin_pwm_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm;
|
struct berlin_pwm_chip *bpc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL);
|
||||||
if (!pwm)
|
if (!bpc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
bpc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(pwm->base))
|
if (IS_ERR(bpc->base))
|
||||||
return PTR_ERR(pwm->base);
|
return PTR_ERR(bpc->base);
|
||||||
|
|
||||||
pwm->clk = devm_clk_get(&pdev->dev, NULL);
|
bpc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(pwm->clk))
|
if (IS_ERR(bpc->clk))
|
||||||
return PTR_ERR(pwm->clk);
|
return PTR_ERR(bpc->clk);
|
||||||
|
|
||||||
ret = clk_prepare_enable(pwm->clk);
|
ret = clk_prepare_enable(bpc->clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
pwm->chip.dev = &pdev->dev;
|
bpc->chip.dev = &pdev->dev;
|
||||||
pwm->chip.ops = &berlin_pwm_ops;
|
bpc->chip.ops = &berlin_pwm_ops;
|
||||||
pwm->chip.npwm = 4;
|
bpc->chip.npwm = 4;
|
||||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pwm->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
ret = pwmchip_add(&pwm->chip);
|
ret = pwmchip_add(&bpc->chip);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||||
clk_disable_unprepare(pwm->clk);
|
clk_disable_unprepare(bpc->clk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pwm);
|
platform_set_drvdata(pdev, bpc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_remove(struct platform_device *pdev)
|
static int berlin_pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev);
|
struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev);
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pwmchip_remove(&pwm->chip);
|
pwmchip_remove(&bpc->chip);
|
||||||
clk_disable_unprepare(pwm->clk);
|
|
||||||
|
|
||||||
return ret;
|
clk_disable_unprepare(bpc->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int berlin_pwm_suspend(struct device *dev)
|
static int berlin_pwm_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
|
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < pwm->chip.npwm; i++) {
|
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||||
struct berlin_pwm_channel *channel;
|
struct berlin_pwm_channel *channel;
|
||||||
|
|
||||||
channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
|
channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
|
||||||
if (!channel)
|
if (!channel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE);
|
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
|
||||||
channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL);
|
channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL);
|
||||||
channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY);
|
channel->duty = berlin_pwm_readl(bpc, i, BERLIN_PWM_DUTY);
|
||||||
channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT);
|
channel->tcnt = berlin_pwm_readl(bpc, i, BERLIN_PWM_TCNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_disable_unprepare(pwm->clk);
|
clk_disable_unprepare(bpc->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int berlin_pwm_resume(struct device *dev)
|
static int berlin_pwm_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
|
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(pwm->clk);
|
ret = clk_prepare_enable(bpc->clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
for (i = 0; i < pwm->chip.npwm; i++) {
|
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||||
struct berlin_pwm_channel *channel;
|
struct berlin_pwm_channel *channel;
|
||||||
|
|
||||||
channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
|
channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
|
||||||
if (!channel)
|
if (!channel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
||||||
berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY);
|
berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY);
|
||||||
berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT);
|
berlin_pwm_writel(bpc, i, channel->tcnt, BERLIN_PWM_TCNT);
|
||||||
berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE);
|
berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -134,16 +134,7 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
spin_lock_init(&priv->lock);
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
return devm_pwmchip_add(&pdev->dev, &priv->chip);
|
||||||
|
|
||||||
return pwmchip_add(&priv->chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clps711x_pwm_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct clps711x_chip *priv = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
return pwmchip_remove(&priv->chip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
|
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
|
||||||
|
@ -158,7 +149,6 @@ static struct platform_driver clps711x_pwm_driver = {
|
||||||
.of_match_table = of_match_ptr(clps711x_pwm_dt_ids),
|
.of_match_table = of_match_ptr(clps711x_pwm_dt_ids),
|
||||||
},
|
},
|
||||||
.probe = clps711x_pwm_probe,
|
.probe = clps711x_pwm_probe,
|
||||||
.remove = clps711x_pwm_remove,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(clps711x_pwm_driver);
|
module_platform_driver(clps711x_pwm_driver);
|
||||||
|
|
||||||
|
|
|
@ -173,21 +173,11 @@ static int crystalcove_pwm_probe(struct platform_device *pdev)
|
||||||
/* get the PMIC regmap */
|
/* get the PMIC regmap */
|
||||||
pwm->regmap = pmic->regmap;
|
pwm->regmap = pmic->regmap;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pwm);
|
return devm_pwmchip_add(&pdev->dev, &pwm->chip);
|
||||||
|
|
||||||
return pwmchip_add(&pwm->chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int crystalcove_pwm_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct crystalcove_pwm *pwm = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
return pwmchip_remove(&pwm->chip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver crystalcove_pwm_driver = {
|
static struct platform_driver crystalcove_pwm_driver = {
|
||||||
.probe = crystalcove_pwm_probe,
|
.probe = crystalcove_pwm_probe,
|
||||||
.remove = crystalcove_pwm_remove,
|
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "crystal_cove_pwm",
|
.name = "crystal_cove_pwm",
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,111 +58,112 @@ static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
ep93xx_pwm_release_gpio(pdev);
|
ep93xx_pwm_release_gpio(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
int duty_ns, int period_ns)
|
const struct pwm_state *state)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
||||||
void __iomem *base = ep93xx_pwm->base;
|
bool enabled = state->enabled;
|
||||||
unsigned long long c;
|
|
||||||
unsigned long period_cycles;
|
if (state->polarity != pwm->state.polarity) {
|
||||||
unsigned long duty_cycles;
|
if (enabled) {
|
||||||
unsigned long term;
|
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
||||||
int ret = 0;
|
clk_disable_unprepare(ep93xx_pwm->clk);
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The clock needs to be enabled to access the PWM registers.
|
||||||
|
* Polarity can only be changed when the PWM is disabled.
|
||||||
|
*/
|
||||||
|
ret = clk_prepare_enable(ep93xx_pwm->clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (state->polarity == PWM_POLARITY_INVERSED)
|
||||||
|
writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
|
||||||
|
else
|
||||||
|
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
|
||||||
|
|
||||||
|
clk_disable_unprepare(ep93xx_pwm->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state->enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
||||||
|
clk_disable_unprepare(ep93xx_pwm->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->period != pwm->state.period ||
|
||||||
|
state->duty_cycle != pwm->state.duty_cycle) {
|
||||||
|
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
||||||
|
void __iomem *base = ep93xx_pwm->base;
|
||||||
|
unsigned long long c;
|
||||||
|
unsigned long period_cycles;
|
||||||
|
unsigned long duty_cycles;
|
||||||
|
unsigned long term;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The clock needs to be enabled to access the PWM registers.
|
||||||
|
* Configuration can be changed at any time.
|
||||||
|
*/
|
||||||
|
if (!pwm_is_enabled(pwm)) {
|
||||||
|
ret = clk_prepare_enable(ep93xx_pwm->clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = clk_get_rate(ep93xx_pwm->clk);
|
||||||
|
c *= state->period;
|
||||||
|
do_div(c, 1000000000);
|
||||||
|
period_cycles = c;
|
||||||
|
|
||||||
|
c = period_cycles;
|
||||||
|
c *= state->duty_cycle;
|
||||||
|
do_div(c, state->period);
|
||||||
|
duty_cycles = c;
|
||||||
|
|
||||||
|
if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
|
||||||
|
term = readw(base + EP93XX_PWMx_TERM_COUNT);
|
||||||
|
|
||||||
|
/* Order is important if PWM is running */
|
||||||
|
if (period_cycles > term) {
|
||||||
|
writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
|
||||||
|
writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
|
||||||
|
} else {
|
||||||
|
writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
|
||||||
|
writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pwm_is_enabled(pwm))
|
||||||
|
clk_disable_unprepare(ep93xx_pwm->clk);
|
||||||
|
|
||||||
/*
|
|
||||||
* The clock needs to be enabled to access the PWM registers.
|
|
||||||
* Configuration can be changed at any time.
|
|
||||||
*/
|
|
||||||
if (!pwm_is_enabled(pwm)) {
|
|
||||||
ret = clk_enable(ep93xx_pwm->clk);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = clk_get_rate(ep93xx_pwm->clk);
|
if (!enabled) {
|
||||||
c *= period_ns;
|
ret = clk_prepare_enable(ep93xx_pwm->clk);
|
||||||
do_div(c, 1000000000);
|
if (ret)
|
||||||
period_cycles = c;
|
return ret;
|
||||||
|
|
||||||
c = period_cycles;
|
writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
||||||
c *= duty_ns;
|
|
||||||
do_div(c, period_ns);
|
|
||||||
duty_cycles = c;
|
|
||||||
|
|
||||||
if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
|
|
||||||
term = readw(base + EP93XX_PWMx_TERM_COUNT);
|
|
||||||
|
|
||||||
/* Order is important if PWM is running */
|
|
||||||
if (period_cycles > term) {
|
|
||||||
writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
|
|
||||||
writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
|
|
||||||
} else {
|
|
||||||
writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
|
|
||||||
writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pwm_is_enabled(pwm))
|
|
||||||
clk_disable(ep93xx_pwm->clk);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ep93xx_pwm_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
||||||
enum pwm_polarity polarity)
|
|
||||||
{
|
|
||||||
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The clock needs to be enabled to access the PWM registers.
|
|
||||||
* Polarity can only be changed when the PWM is disabled.
|
|
||||||
*/
|
|
||||||
ret = clk_enable(ep93xx_pwm->clk);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (polarity == PWM_POLARITY_INVERSED)
|
|
||||||
writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
|
|
||||||
else
|
|
||||||
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
|
|
||||||
|
|
||||||
clk_disable(ep93xx_pwm->clk);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ep93xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|
||||||
{
|
|
||||||
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = clk_enable(ep93xx_pwm->clk);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ep93xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|
||||||
{
|
|
||||||
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
|
|
||||||
|
|
||||||
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
|
||||||
clk_disable(ep93xx_pwm->clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pwm_ops ep93xx_pwm_ops = {
|
static const struct pwm_ops ep93xx_pwm_ops = {
|
||||||
.request = ep93xx_pwm_request,
|
.request = ep93xx_pwm_request,
|
||||||
.free = ep93xx_pwm_free,
|
.free = ep93xx_pwm_free,
|
||||||
.config = ep93xx_pwm_config,
|
.apply = ep93xx_pwm_apply,
|
||||||
.set_polarity = ep93xx_pwm_polarity,
|
|
||||||
.enable = ep93xx_pwm_enable,
|
|
||||||
.disable = ep93xx_pwm_disable,
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -451,8 +451,6 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
|
|
||||||
fpc->chip.ops = &fsl_pwm_ops;
|
fpc->chip.ops = &fsl_pwm_ops;
|
||||||
fpc->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
fpc->chip.of_pwm_n_cells = 3;
|
|
||||||
fpc->chip.npwm = 8;
|
fpc->chip.npwm = 8;
|
||||||
|
|
||||||
ret = pwmchip_add(&fpc->chip);
|
ret = pwmchip_add(&fpc->chip);
|
||||||
|
|
|
@ -206,8 +206,6 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
|
||||||
pwm_chip->chip.ops = &hibvt_pwm_ops;
|
pwm_chip->chip.ops = &hibvt_pwm_ops;
|
||||||
pwm_chip->chip.dev = &pdev->dev;
|
pwm_chip->chip.dev = &pdev->dev;
|
||||||
pwm_chip->chip.npwm = soc->num_pwms;
|
pwm_chip->chip.npwm = soc->num_pwms;
|
||||||
pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pwm_chip->chip.of_pwm_n_cells = 3;
|
|
||||||
pwm_chip->soc = soc;
|
pwm_chip->soc = soc;
|
||||||
|
|
||||||
pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
|
pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
|
|
@ -156,7 +156,7 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
|
struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(chip->dev);
|
ret = pm_runtime_resume_and_get(chip->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -363,8 +363,6 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
tpm->chip.dev = &pdev->dev;
|
tpm->chip.dev = &pdev->dev;
|
||||||
tpm->chip.ops = &imx_tpm_pwm_ops;
|
tpm->chip.ops = &imx_tpm_pwm_ops;
|
||||||
tpm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
tpm->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
/* get number of channels */
|
/* get number of channels */
|
||||||
val = readl(tpm->base + PWM_IMX_TPM_PARAM);
|
val = readl(tpm->base + PWM_IMX_TPM_PARAM);
|
||||||
|
|
|
@ -141,8 +141,6 @@ static int pwm_imx1_probe(struct platform_device *pdev)
|
||||||
if (!imx)
|
if (!imx)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, imx);
|
|
||||||
|
|
||||||
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||||
if (IS_ERR(imx->clk_ipg))
|
if (IS_ERR(imx->clk_ipg))
|
||||||
return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg),
|
return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg),
|
||||||
|
@ -161,16 +159,7 @@ static int pwm_imx1_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(imx->mmio_base))
|
if (IS_ERR(imx->mmio_base))
|
||||||
return PTR_ERR(imx->mmio_base);
|
return PTR_ERR(imx->mmio_base);
|
||||||
|
|
||||||
return pwmchip_add(&imx->chip);
|
return devm_pwmchip_add(&pdev->dev, &imx->chip);
|
||||||
}
|
|
||||||
|
|
||||||
static int pwm_imx1_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct pwm_imx1_chip *imx = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
pwm_imx1_clk_disable_unprepare(&imx->chip);
|
|
||||||
|
|
||||||
return pwmchip_remove(&imx->chip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver pwm_imx1_driver = {
|
static struct platform_driver pwm_imx1_driver = {
|
||||||
|
@ -179,7 +168,6 @@ static struct platform_driver pwm_imx1_driver = {
|
||||||
.of_match_table = pwm_imx1_dt_ids,
|
.of_match_table = pwm_imx1_dt_ids,
|
||||||
},
|
},
|
||||||
.probe = pwm_imx1_probe,
|
.probe = pwm_imx1_probe,
|
||||||
.remove = pwm_imx1_remove,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(pwm_imx1_driver);
|
module_platform_driver(pwm_imx1_driver);
|
||||||
|
|
||||||
|
|
|
@ -329,9 +329,6 @@ static int pwm_imx27_probe(struct platform_device *pdev)
|
||||||
imx->chip.dev = &pdev->dev;
|
imx->chip.dev = &pdev->dev;
|
||||||
imx->chip.npwm = 1;
|
imx->chip.npwm = 1;
|
||||||
|
|
||||||
imx->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
imx->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(imx->mmio_base))
|
if (IS_ERR(imx->mmio_base))
|
||||||
return PTR_ERR(imx->mmio_base);
|
return PTR_ERR(imx->mmio_base);
|
||||||
|
|
|
@ -244,8 +244,6 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
|
||||||
jz4740->chip.dev = dev;
|
jz4740->chip.dev = dev;
|
||||||
jz4740->chip.ops = &jz4740_pwm_ops;
|
jz4740->chip.ops = &jz4740_pwm_ops;
|
||||||
jz4740->chip.npwm = info->num_pwms;
|
jz4740->chip.npwm = info->num_pwms;
|
||||||
jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
jz4740->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, jz4740);
|
platform_set_drvdata(pdev, jz4740);
|
||||||
|
|
||||||
|
|
|
@ -371,8 +371,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||||
lpc18xx_pwm->chip.dev = &pdev->dev;
|
lpc18xx_pwm->chip.dev = &pdev->dev;
|
||||||
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
|
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
|
||||||
lpc18xx_pwm->chip.npwm = 16;
|
lpc18xx_pwm->chip.npwm = 16;
|
||||||
lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
lpc18xx_pwm->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
/* SCT counter must be in unify (32 bit) mode */
|
/* SCT counter must be in unify (32 bit) mode */
|
||||||
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
|
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
|
||||||
|
|
|
@ -69,12 +69,8 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
|
||||||
|
|
||||||
static void pwm_lpss_remove_pci(struct pci_dev *pdev)
|
static void pwm_lpss_remove_pci(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
|
|
||||||
|
|
||||||
pm_runtime_forbid(&pdev->dev);
|
pm_runtime_forbid(&pdev->dev);
|
||||||
pm_runtime_get_sync(&pdev->dev);
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
|
|
||||||
pwm_lpss_remove(lpwm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
|
@ -85,10 +85,8 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
|
||||||
|
|
||||||
static int pwm_lpss_remove_platform(struct platform_device *pdev)
|
static int pwm_lpss_remove_platform(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
return pwm_lpss_remove(lpwm);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
|
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
|
||||||
|
|
|
@ -236,7 +236,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
||||||
lpwm->chip.ops = &pwm_lpss_ops;
|
lpwm->chip.ops = &pwm_lpss_ops;
|
||||||
lpwm->chip.npwm = info->npwm;
|
lpwm->chip.npwm = info->npwm;
|
||||||
|
|
||||||
ret = pwmchip_add(&lpwm->chip);
|
ret = devm_pwmchip_add(dev, &lpwm->chip);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to add PWM chip: %d\n", ret);
|
dev_err(dev, "failed to add PWM chip: %d\n", ret);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
@ -252,12 +252,6 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pwm_lpss_probe);
|
EXPORT_SYMBOL_GPL(pwm_lpss_probe);
|
||||||
|
|
||||||
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
|
|
||||||
{
|
|
||||||
return pwmchip_remove(&lpwm->chip);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("PWM driver for Intel LPSS");
|
MODULE_DESCRIPTION("PWM driver for Intel LPSS");
|
||||||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -35,6 +35,5 @@ struct pwm_lpss_boardinfo {
|
||||||
|
|
||||||
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
||||||
const struct pwm_lpss_boardinfo *info);
|
const struct pwm_lpss_boardinfo *info);
|
||||||
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
|
|
||||||
|
|
||||||
#endif /* __PWM_LPSS_H */
|
#endif /* __PWM_LPSS_H */
|
||||||
|
|
|
@ -551,8 +551,6 @@ static int meson_pwm_probe(struct platform_device *pdev)
|
||||||
meson->chip.dev = &pdev->dev;
|
meson->chip.dev = &pdev->dev;
|
||||||
meson->chip.ops = &meson_pwm_ops;
|
meson->chip.ops = &meson_pwm_ops;
|
||||||
meson->chip.npwm = MESON_NUM_PWMS;
|
meson->chip.npwm = MESON_NUM_PWMS;
|
||||||
meson->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
meson->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
meson->data = of_device_get_match_data(&pdev->dev);
|
meson->data = of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
|
@ -560,31 +558,21 @@ static int meson_pwm_probe(struct platform_device *pdev)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = pwmchip_add(&meson->chip);
|
err = devm_pwmchip_add(&pdev->dev, &meson->chip);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
|
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, meson);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meson_pwm_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct meson_pwm *meson = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
return pwmchip_remove(&meson->chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct platform_driver meson_pwm_driver = {
|
static struct platform_driver meson_pwm_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "meson-pwm",
|
.name = "meson-pwm",
|
||||||
.of_match_table = meson_pwm_matches,
|
.of_match_table = meson_pwm_matches,
|
||||||
},
|
},
|
||||||
.probe = meson_pwm_probe,
|
.probe = meson_pwm_probe,
|
||||||
.remove = meson_pwm_remove,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(meson_pwm_driver);
|
module_platform_driver(meson_pwm_driver);
|
||||||
|
|
||||||
|
|
|
@ -138,8 +138,6 @@ static int mxs_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
mxs->chip.dev = &pdev->dev;
|
mxs->chip.dev = &pdev->dev;
|
||||||
mxs->chip.ops = &mxs_pwm_ops;
|
mxs->chip.ops = &mxs_pwm_ops;
|
||||||
mxs->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
mxs->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
|
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -404,8 +404,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||||
omap->chip.dev = &pdev->dev;
|
omap->chip.dev = &pdev->dev;
|
||||||
omap->chip.ops = &pwm_omap_dmtimer_ops;
|
omap->chip.ops = &pwm_omap_dmtimer_ops;
|
||||||
omap->chip.npwm = 1;
|
omap->chip.npwm = 1;
|
||||||
omap->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
omap->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
mutex_init(&omap->mutex);
|
mutex_init(&omap->mutex);
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Because the PCA9685 has only one prescaler per chip, changing the period of
|
* Because the PCA9685 has only one prescaler per chip, only the first channel
|
||||||
* one channel affects the period of all 16 PWM outputs!
|
* that is enabled is allowed to change the prescale register.
|
||||||
* However, the ratio between each configured duty cycle and the chip-wide
|
* PWM channels requested afterwards must use a period that results in the same
|
||||||
* period remains constant, because the OFF time is set in proportion to the
|
* prescale setting as the one set by the first requested channel.
|
||||||
* counter range.
|
* GPIOs do not count as enabled PWMs as they are not using the prescaler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PCA9685_MODE1 0x00
|
#define PCA9685_MODE1 0x00
|
||||||
|
@ -78,8 +78,9 @@
|
||||||
struct pca9685 {
|
struct pca9685 {
|
||||||
struct pwm_chip chip;
|
struct pwm_chip chip;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
|
||||||
|
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||||
struct gpio_chip gpio;
|
struct gpio_chip gpio;
|
||||||
DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
|
DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,51 +91,120 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
|
||||||
return container_of(chip, struct pca9685, chip);
|
return container_of(chip, struct pca9685, chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function is supposed to be called with the lock mutex held */
|
||||||
|
static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel)
|
||||||
|
{
|
||||||
|
/* No PWM enabled: Change allowed */
|
||||||
|
if (bitmap_empty(pca->pwms_enabled, PCA9685_MAXCHAN + 1))
|
||||||
|
return true;
|
||||||
|
/* More than one PWM enabled: Change not allowed */
|
||||||
|
if (bitmap_weight(pca->pwms_enabled, PCA9685_MAXCHAN + 1) > 1)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* Only one PWM enabled: Change allowed if the PWM about to
|
||||||
|
* be changed is the one that is already enabled
|
||||||
|
*/
|
||||||
|
return test_bit(channel, pca->pwms_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned int *val)
|
||||||
|
{
|
||||||
|
struct device *dev = pca->chip.dev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = regmap_read(pca->regmap, reg, val);
|
||||||
|
if (err)
|
||||||
|
dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, ERR_PTR(err));
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int val)
|
||||||
|
{
|
||||||
|
struct device *dev = pca->chip.dev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = regmap_write(pca->regmap, reg, val);
|
||||||
|
if (err)
|
||||||
|
dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
|
/* 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 pca9685 *pca, int channel, unsigned int duty)
|
||||||
{
|
{
|
||||||
|
struct pwm_device *pwm = &pca->chip.pwms[channel];
|
||||||
|
unsigned int on, off;
|
||||||
|
|
||||||
if (duty == 0) {
|
if (duty == 0) {
|
||||||
/* Set the full OFF bit, which has the highest precedence */
|
/* Set the full OFF bit, which has the highest precedence */
|
||||||
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
|
pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
|
||||||
|
return;
|
||||||
} else if (duty >= PCA9685_COUNTER_RANGE) {
|
} else if (duty >= PCA9685_COUNTER_RANGE) {
|
||||||
/* Set the full ON bit and clear the full OFF bit */
|
/* Set the full ON bit and clear the full OFF bit */
|
||||||
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
|
pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
|
||||||
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
|
pca9685_write_reg(pca, REG_OFF_H(channel), 0);
|
||||||
} else {
|
return;
|
||||||
/* Set OFF time (clears the full OFF bit) */
|
|
||||||
regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
|
|
||||||
regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf);
|
|
||||||
/* Clear the full ON bit */
|
|
||||||
regmap_write(pca->regmap, REG_ON_H(channel), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) {
|
||||||
|
/*
|
||||||
|
* If usage_power is set, the pca9685 driver will phase shift
|
||||||
|
* the individual channels relative to their channel number.
|
||||||
|
* This improves EMI because the enabled channels no longer
|
||||||
|
* turn on at the same time, while still maintaining the
|
||||||
|
* configured duty cycle / power output.
|
||||||
|
*/
|
||||||
|
on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
|
||||||
|
} else
|
||||||
|
on = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
|
static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
|
||||||
{
|
{
|
||||||
unsigned int off_h = 0, val = 0;
|
struct pwm_device *pwm = &pca->chip.pwms[channel];
|
||||||
|
unsigned int off = 0, on = 0, val = 0;
|
||||||
|
|
||||||
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
|
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
|
||||||
/* HW does not support reading state of "all LEDs" channel */
|
/* HW does not support reading state of "all LEDs" channel */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
regmap_read(pca->regmap, LED_N_OFF_H(channel), &off_h);
|
pca9685_read_reg(pca, LED_N_OFF_H(channel), &off);
|
||||||
if (off_h & LED_FULL) {
|
if (off & LED_FULL) {
|
||||||
/* Full OFF bit is set */
|
/* Full OFF bit is set */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
regmap_read(pca->regmap, LED_N_ON_H(channel), &val);
|
pca9685_read_reg(pca, LED_N_ON_H(channel), &on);
|
||||||
if (val & LED_FULL) {
|
if (on & LED_FULL) {
|
||||||
/* Full ON bit is set */
|
/* Full ON bit is set */
|
||||||
return PCA9685_COUNTER_RANGE;
|
return PCA9685_COUNTER_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regmap_read(pca->regmap, LED_N_OFF_L(channel), &val)) {
|
pca9685_read_reg(pca, LED_N_OFF_L(channel), &val);
|
||||||
/* Reset val to 0 in case reading LED_N_OFF_L failed */
|
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)) {
|
||||||
|
/* Reset val to 0 in case reading LED_N_ON_L failed */
|
||||||
val = 0;
|
val = 0;
|
||||||
}
|
}
|
||||||
return ((off_h & 0xf) << 8) | (val & 0xff);
|
on = ((on & 0xf) << 8) | (val & 0xff);
|
||||||
|
return (off - on) & (PCA9685_COUNTER_RANGE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||||
|
@ -240,8 +310,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||||
{
|
{
|
||||||
struct device *dev = pca->chip.dev;
|
struct device *dev = pca->chip.dev;
|
||||||
|
|
||||||
mutex_init(&pca->lock);
|
|
||||||
|
|
||||||
pca->gpio.label = dev_name(dev);
|
pca->gpio.label = dev_name(dev);
|
||||||
pca->gpio.parent = dev;
|
pca->gpio.parent = dev;
|
||||||
pca->gpio.request = pca9685_pwm_gpio_request;
|
pca->gpio.request = pca9685_pwm_gpio_request;
|
||||||
|
@ -277,16 +345,23 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||||
|
|
||||||
static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
|
static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
|
||||||
{
|
{
|
||||||
regmap_update_bits(pca->regmap, PCA9685_MODE1,
|
struct device *dev = pca->chip.dev;
|
||||||
MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
|
int err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
|
||||||
|
MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "regmap_update_bits of register 0x%x failed: %pe\n",
|
||||||
|
PCA9685_MODE1, ERR_PTR(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
/* Wait 500us for the oscillator to be back up */
|
/* Wait 500us for the oscillator to be back up */
|
||||||
udelay(500);
|
udelay(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
const struct pwm_state *state)
|
const struct pwm_state *state)
|
||||||
{
|
{
|
||||||
struct pca9685 *pca = to_pca(chip);
|
struct pca9685 *pca = to_pca(chip);
|
||||||
unsigned long long duty, prescale;
|
unsigned long long duty, prescale;
|
||||||
|
@ -307,8 +382,14 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
|
pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
|
||||||
if (prescale != val) {
|
if (prescale != val) {
|
||||||
|
if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
|
||||||
|
dev_err(chip->dev,
|
||||||
|
"pwm not changed: periods of enabled pwms must match!\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Putting the chip briefly into SLEEP mode
|
* Putting the chip briefly into SLEEP mode
|
||||||
* at this point won't interfere with the
|
* at this point won't interfere with the
|
||||||
|
@ -319,7 +400,7 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
pca9685_set_sleep_mode(pca, true);
|
pca9685_set_sleep_mode(pca, true);
|
||||||
|
|
||||||
/* Change the chip-wide output frequency */
|
/* Change the chip-wide output frequency */
|
||||||
regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
|
pca9685_write_reg(pca, PCA9685_PRESCALE, prescale);
|
||||||
|
|
||||||
/* Wake the chip up */
|
/* Wake the chip up */
|
||||||
pca9685_set_sleep_mode(pca, false);
|
pca9685_set_sleep_mode(pca, false);
|
||||||
|
@ -331,6 +412,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
const struct pwm_state *state)
|
||||||
|
{
|
||||||
|
struct pca9685 *pca = to_pca(chip);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&pca->lock);
|
||||||
|
ret = __pca9685_pwm_apply(chip, pwm, state);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (state->enabled)
|
||||||
|
set_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||||
|
else
|
||||||
|
clear_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||||
|
}
|
||||||
|
mutex_unlock(&pca->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
struct pwm_state *state)
|
struct pwm_state *state)
|
||||||
{
|
{
|
||||||
|
@ -339,7 +439,7 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
unsigned int val = 0;
|
unsigned int val = 0;
|
||||||
|
|
||||||
/* Calculate (chip-wide) period from prescale value */
|
/* Calculate (chip-wide) period from prescale value */
|
||||||
regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
|
pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
|
||||||
/*
|
/*
|
||||||
* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
|
* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
|
||||||
* The following calculation is therefore only a multiplication
|
* The following calculation is therefore only a multiplication
|
||||||
|
@ -372,6 +472,14 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
|
|
||||||
if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
|
if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (pwm->hwpwm < PCA9685_MAXCHAN) {
|
||||||
|
/* PWMs - except the "all LEDs" channel - default to enabled */
|
||||||
|
mutex_lock(&pca->lock);
|
||||||
|
set_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||||
|
mutex_unlock(&pca->lock);
|
||||||
|
}
|
||||||
|
|
||||||
pm_runtime_get_sync(chip->dev);
|
pm_runtime_get_sync(chip->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -381,7 +489,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
{
|
{
|
||||||
struct pca9685 *pca = to_pca(chip);
|
struct pca9685 *pca = to_pca(chip);
|
||||||
|
|
||||||
|
mutex_lock(&pca->lock);
|
||||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||||
|
clear_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||||
|
mutex_unlock(&pca->lock);
|
||||||
|
|
||||||
pm_runtime_put(chip->dev);
|
pm_runtime_put(chip->dev);
|
||||||
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
|
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
|
||||||
}
|
}
|
||||||
|
@ -422,7 +534,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
||||||
|
|
||||||
i2c_set_clientdata(client, pca);
|
i2c_set_clientdata(client, pca);
|
||||||
|
|
||||||
regmap_read(pca->regmap, PCA9685_MODE2, ®);
|
mutex_init(&pca->lock);
|
||||||
|
|
||||||
|
ret = pca9685_read_reg(pca, PCA9685_MODE2, ®);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (device_property_read_bool(&client->dev, "invert"))
|
if (device_property_read_bool(&client->dev, "invert"))
|
||||||
reg |= MODE2_INVRT;
|
reg |= MODE2_INVRT;
|
||||||
|
@ -434,16 +550,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
||||||
else
|
else
|
||||||
reg |= MODE2_OUTDRV;
|
reg |= MODE2_OUTDRV;
|
||||||
|
|
||||||
regmap_write(pca->regmap, PCA9685_MODE2, reg);
|
ret = pca9685_write_reg(pca, PCA9685_MODE2, reg);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
|
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
|
||||||
regmap_read(pca->regmap, PCA9685_MODE1, ®);
|
pca9685_read_reg(pca, PCA9685_MODE1, ®);
|
||||||
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
|
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
|
||||||
regmap_write(pca->regmap, PCA9685_MODE1, reg);
|
pca9685_write_reg(pca, PCA9685_MODE1, reg);
|
||||||
|
|
||||||
/* Reset OFF registers to POR default */
|
/* Reset OFF/ON registers to POR default */
|
||||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
|
pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, LED_FULL);
|
||||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
|
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, 0);
|
||||||
|
|
||||||
pca->chip.ops = &pca9685_pwm_ops;
|
pca->chip.ops = &pca9685_pwm_ops;
|
||||||
/* Add an extra channel for ALL_LED */
|
/* Add an extra channel for ALL_LED */
|
||||||
|
|
|
@ -165,7 +165,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||||
static int pwm_probe(struct platform_device *pdev)
|
static int pwm_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||||
struct pxa_pwm_chip *pwm;
|
struct pxa_pwm_chip *pc;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_OF) && id == NULL)
|
if (IS_ENABLED(CONFIG_OF) && id == NULL)
|
||||||
|
@ -174,46 +174,44 @@ static int pwm_probe(struct platform_device *pdev)
|
||||||
if (id == NULL)
|
if (id == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||||
if (pwm == NULL)
|
if (pc == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pwm->clk = devm_clk_get(&pdev->dev, NULL);
|
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(pwm->clk))
|
if (IS_ERR(pc->clk))
|
||||||
return PTR_ERR(pwm->clk);
|
return PTR_ERR(pc->clk);
|
||||||
|
|
||||||
pwm->chip.dev = &pdev->dev;
|
pc->chip.dev = &pdev->dev;
|
||||||
pwm->chip.ops = &pxa_pwm_ops;
|
pc->chip.ops = &pxa_pwm_ops;
|
||||||
pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_OF)) {
|
if (IS_ENABLED(CONFIG_OF)) {
|
||||||
pwm->chip.of_xlate = pxa_pwm_of_xlate;
|
pc->chip.of_xlate = pxa_pwm_of_xlate;
|
||||||
pwm->chip.of_pwm_n_cells = 1;
|
pc->chip.of_pwm_n_cells = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwm->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(pwm->mmio_base))
|
if (IS_ERR(pc->mmio_base))
|
||||||
return PTR_ERR(pwm->mmio_base);
|
return PTR_ERR(pc->mmio_base);
|
||||||
|
|
||||||
ret = pwmchip_add(&pwm->chip);
|
ret = pwmchip_add(&pc->chip);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pwm);
|
platform_set_drvdata(pdev, pc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pwm_remove(struct platform_device *pdev)
|
static int pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct pxa_pwm_chip *chip;
|
struct pxa_pwm_chip *pc;
|
||||||
|
|
||||||
chip = platform_get_drvdata(pdev);
|
pc = platform_get_drvdata(pdev);
|
||||||
if (chip == NULL)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return pwmchip_remove(&chip->chip);
|
return pwmchip_remove(&pc->chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver pwm_driver = {
|
static struct platform_driver pwm_driver = {
|
||||||
|
|
|
@ -408,8 +408,6 @@ static int tpu_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
tpu->chip.dev = &pdev->dev;
|
tpu->chip.dev = &pdev->dev;
|
||||||
tpu->chip.ops = &tpu_pwm_ops;
|
tpu->chip.ops = &tpu_pwm_ops;
|
||||||
tpu->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
tpu->chip.of_pwm_n_cells = 3;
|
|
||||||
tpu->chip.npwm = TPU_CHANNEL_MAX;
|
tpu->chip.npwm = TPU_CHANNEL_MAX;
|
||||||
|
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
|
@ -354,11 +354,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||||
pc->chip.ops = &rockchip_pwm_ops;
|
pc->chip.ops = &rockchip_pwm_ops;
|
||||||
pc->chip.npwm = 1;
|
pc->chip.npwm = 1;
|
||||||
|
|
||||||
if (pc->data->supports_polarity) {
|
|
||||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pc->chip.of_pwm_n_cells = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
enable_conf = pc->data->enable_conf;
|
enable_conf = pc->data->enable_conf;
|
||||||
ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
|
ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
|
||||||
enabled = (ctrl & enable_conf) == enable_conf;
|
enabled = (ctrl & enable_conf) == enable_conf;
|
||||||
|
|
|
@ -526,9 +526,6 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||||
ret = pwm_samsung_parse_dt(chip);
|
ret = pwm_samsung_parse_dt(chip);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
chip->chip.of_pwm_n_cells = 3;
|
|
||||||
} else {
|
} else {
|
||||||
if (!pdev->dev.platform_data) {
|
if (!pdev->dev.platform_data) {
|
||||||
dev_err(&pdev->dev, "no platform data specified\n");
|
dev_err(&pdev->dev, "no platform data specified\n");
|
||||||
|
|
|
@ -242,8 +242,6 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||||
chip = &ddata->chip;
|
chip = &ddata->chip;
|
||||||
chip->dev = dev;
|
chip->dev = dev;
|
||||||
chip->ops = &pwm_sifive_ops;
|
chip->ops = &pwm_sifive_ops;
|
||||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
chip->of_pwm_n_cells = 3;
|
|
||||||
chip->npwm = 4;
|
chip->npwm = 4;
|
||||||
|
|
||||||
ddata->regs = devm_platform_ioremap_resource(pdev, 0);
|
ddata->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
|
|
@ -75,7 +75,7 @@ static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
int duty_ns, int period_ns)
|
u64 duty_ns, u64 period_ns)
|
||||||
{
|
{
|
||||||
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
|
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
|
||||||
u64 val, div, clk_rate;
|
u64 val, div, clk_rate;
|
||||||
|
@ -163,10 +163,35 @@ static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
clk_disable(pc->clk);
|
clk_disable(pc->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int spear_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
const struct pwm_state *state)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!state->enabled) {
|
||||||
|
if (pwm->state.enabled)
|
||||||
|
spear_pwm_disable(chip, pwm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->period != pwm->state.period ||
|
||||||
|
state->duty_cycle != pwm->state.duty_cycle) {
|
||||||
|
err = spear_pwm_config(chip, pwm, state->duty_cycle, state->period);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pwm->state.enabled)
|
||||||
|
return spear_pwm_enable(chip, pwm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pwm_ops spear_pwm_ops = {
|
static const struct pwm_ops spear_pwm_ops = {
|
||||||
.config = spear_pwm_config,
|
.apply = spear_pwm_apply,
|
||||||
.enable = spear_pwm_enable,
|
|
||||||
.disable = spear_pwm_disable,
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -228,14 +253,13 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
||||||
static int spear_pwm_remove(struct platform_device *pdev)
|
static int spear_pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
|
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_PWM; i++)
|
pwmchip_remove(&pc->chip);
|
||||||
pwm_disable(&pc->chip.pwms[i]);
|
|
||||||
|
|
||||||
/* clk was prepared in probe, hence unprepare it here */
|
/* clk was prepared in probe, hence unprepare it here */
|
||||||
clk_unprepare(pc->clk);
|
clk_unprepare(pc->clk);
|
||||||
return pwmchip_remove(&pc->chip);
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id spear_pwm_of_match[] = {
|
static const struct of_device_id spear_pwm_of_match[] = {
|
||||||
|
|
|
@ -284,7 +284,9 @@ static int sprd_pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
|
struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
return pwmchip_remove(&spc->chip);
|
pwmchip_remove(&spc->chip);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sprd_pwm_of_match[] = {
|
static const struct of_device_id sprd_pwm_of_match[] = {
|
||||||
|
|
|
@ -208,8 +208,6 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
|
||||||
priv->chip.dev = &pdev->dev;
|
priv->chip.dev = &pdev->dev;
|
||||||
priv->chip.ops = &stm32_pwm_lp_ops;
|
priv->chip.ops = &stm32_pwm_lp_ops;
|
||||||
priv->chip.npwm = 1;
|
priv->chip.npwm = 1;
|
||||||
priv->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
priv->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
ret = pwmchip_add(&priv->chip);
|
ret = pwmchip_add(&priv->chip);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -621,8 +621,6 @@ static int stm32_pwm_probe(struct platform_device *pdev)
|
||||||
priv->regmap = ddata->regmap;
|
priv->regmap = ddata->regmap;
|
||||||
priv->clk = ddata->clk;
|
priv->clk = ddata->clk;
|
||||||
priv->max_arr = ddata->max_arr;
|
priv->max_arr = ddata->max_arr;
|
||||||
priv->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
priv->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
if (!priv->regmap || !priv->clk)
|
if (!priv->regmap || !priv->clk)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -460,8 +460,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
|
||||||
pwm->chip.dev = &pdev->dev;
|
pwm->chip.dev = &pdev->dev;
|
||||||
pwm->chip.ops = &sun4i_pwm_ops;
|
pwm->chip.ops = &sun4i_pwm_ops;
|
||||||
pwm->chip.npwm = pwm->data->npwm;
|
pwm->chip.npwm = pwm->data->npwm;
|
||||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pwm->chip.of_pwm_n_cells = 3;
|
|
||||||
|
|
||||||
spin_lock_init(&pwm->ctrl_lock);
|
spin_lock_init(&pwm->ctrl_lock);
|
||||||
|
|
||||||
|
|
|
@ -300,32 +300,12 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
||||||
static int tegra_pwm_remove(struct platform_device *pdev)
|
static int tegra_pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
|
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||||
unsigned int i;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (WARN_ON(!pc))
|
pwmchip_remove(&pc->chip);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
err = clk_prepare_enable(pc->clk);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
for (i = 0; i < pc->chip.npwm; i++) {
|
|
||||||
struct pwm_device *pwm = &pc->chip.pwms[i];
|
|
||||||
|
|
||||||
if (!pwm_is_enabled(pwm))
|
|
||||||
if (clk_prepare_enable(pc->clk) < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pwm_writel(pc, i, 0);
|
|
||||||
|
|
||||||
clk_disable_unprepare(pc->clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_control_assert(pc->rst);
|
reset_control_assert(pc->rst);
|
||||||
clk_disable_unprepare(pc->clk);
|
|
||||||
|
|
||||||
return pwmchip_remove(&pc->chip);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
|
@ -48,16 +48,13 @@ static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
|
||||||
* duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE
|
* duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE
|
||||||
*/
|
*/
|
||||||
static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
int duty_ns, int period_ns)
|
int duty_ns, int period_ns, int enabled)
|
||||||
{
|
{
|
||||||
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
|
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
|
||||||
u32 period_cycles, duty_cycles;
|
u32 period_cycles, duty_cycles;
|
||||||
unsigned long long c;
|
unsigned long long c;
|
||||||
u16 value;
|
u16 value;
|
||||||
|
|
||||||
if (period_ns > NSEC_PER_SEC)
|
|
||||||
return -ERANGE;
|
|
||||||
|
|
||||||
c = pc->clk_rate;
|
c = pc->clk_rate;
|
||||||
c = c * period_ns;
|
c = c * period_ns;
|
||||||
do_div(c, NSEC_PER_SEC);
|
do_div(c, NSEC_PER_SEC);
|
||||||
|
@ -82,7 +79,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
|
||||||
writew(value, pc->mmio_base + ECCTL2);
|
writew(value, pc->mmio_base + ECCTL2);
|
||||||
|
|
||||||
if (!pwm_is_enabled(pwm)) {
|
if (!enabled) {
|
||||||
/* Update active registers if not running */
|
/* Update active registers if not running */
|
||||||
writel(duty_cycles, pc->mmio_base + CAP2);
|
writel(duty_cycles, pc->mmio_base + CAP2);
|
||||||
writel(period_cycles, pc->mmio_base + CAP1);
|
writel(period_cycles, pc->mmio_base + CAP1);
|
||||||
|
@ -96,7 +93,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
writel(period_cycles, pc->mmio_base + CAP3);
|
writel(period_cycles, pc->mmio_base + CAP3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pwm_is_enabled(pwm)) {
|
if (!enabled) {
|
||||||
value = readw(pc->mmio_base + ECCTL2);
|
value = readw(pc->mmio_base + ECCTL2);
|
||||||
/* Disable APWM mode to put APWM output Low */
|
/* Disable APWM mode to put APWM output Low */
|
||||||
value &= ~ECCTL2_APWM_MODE;
|
value &= ~ECCTL2_APWM_MODE;
|
||||||
|
@ -168,20 +165,49 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
pm_runtime_put_sync(pc->chip.dev);
|
pm_runtime_put_sync(pc->chip.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
const struct pwm_state *state)
|
||||||
{
|
{
|
||||||
if (pwm_is_enabled(pwm)) {
|
int err;
|
||||||
dev_warn(chip->dev, "Removing PWM device without disabling\n");
|
int enabled = pwm->state.enabled;
|
||||||
pm_runtime_put_sync(chip->dev);
|
|
||||||
|
if (state->polarity != pwm->state.polarity) {
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
ecap_pwm_disable(chip, pwm);
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ecap_pwm_set_polarity(chip, pwm, state->polarity);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!state->enabled) {
|
||||||
|
if (enabled)
|
||||||
|
ecap_pwm_disable(chip, pwm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->period != pwm->state.period ||
|
||||||
|
state->duty_cycle != pwm->state.duty_cycle) {
|
||||||
|
if (state->period > NSEC_PER_SEC)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
err = ecap_pwm_config(chip, pwm, state->duty_cycle,
|
||||||
|
state->period, enabled);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return ecap_pwm_enable(chip, pwm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pwm_ops ecap_pwm_ops = {
|
static const struct pwm_ops ecap_pwm_ops = {
|
||||||
.free = ecap_pwm_free,
|
.apply = ecap_pwm_apply,
|
||||||
.config = ecap_pwm_config,
|
|
||||||
.set_polarity = ecap_pwm_set_polarity,
|
|
||||||
.enable = ecap_pwm_enable,
|
|
||||||
.disable = ecap_pwm_disable,
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,8 +250,6 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
pc->chip.dev = &pdev->dev;
|
pc->chip.dev = &pdev->dev;
|
||||||
pc->chip.ops = &ecap_pwm_ops;
|
pc->chip.ops = &ecap_pwm_ops;
|
||||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pc->chip.of_pwm_n_cells = 3;
|
|
||||||
pc->chip.npwm = 1;
|
pc->chip.npwm = 1;
|
||||||
|
|
||||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
|
|
@ -447,8 +447,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
pc->chip.dev = &pdev->dev;
|
pc->chip.dev = &pdev->dev;
|
||||||
pc->chip.ops = &ehrpwm_pwm_ops;
|
pc->chip.ops = &ehrpwm_pwm_ops;
|
||||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
pc->chip.of_pwm_n_cells = 3;
|
|
||||||
pc->chip.npwm = NUM_PWM_CHANNEL;
|
pc->chip.npwm = NUM_PWM_CHANNEL;
|
||||||
|
|
||||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
|
|
@ -82,17 +82,14 @@ static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PWMC controls a divider that divides the input clk by a
|
* PWMC controls a divider that divides the input clk by a power of two
|
||||||
* power of two between 1 and 8. As a smaller divider yields
|
* between 1 and 8. As a smaller divider yields higher precision, pick
|
||||||
* higher precision, pick the smallest possible one.
|
* the smallest possible one. As period is at most 0xffff << 3, pwmc0 is
|
||||||
|
* in the intended range [0..3].
|
||||||
*/
|
*/
|
||||||
if (period > 0xffff) {
|
pwmc0 = fls(period >> 16);
|
||||||
pwmc0 = ilog2(period >> 16);
|
if (WARN_ON(pwmc0 > 3))
|
||||||
if (WARN_ON(pwmc0 > 3))
|
return -EINVAL;
|
||||||
return -EINVAL;
|
|
||||||
} else {
|
|
||||||
pwmc0 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
period >>= pwmc0;
|
period >>= pwmc0;
|
||||||
duty_cycle >>= pwmc0;
|
duty_cycle >>= pwmc0;
|
||||||
|
|
|
@ -207,8 +207,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
chip->chip.dev = &pdev->dev;
|
chip->chip.dev = &pdev->dev;
|
||||||
chip->chip.ops = &vt8500_pwm_ops;
|
chip->chip.ops = &vt8500_pwm_ops;
|
||||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
|
||||||
chip->chip.of_pwm_n_cells = 3;
|
|
||||||
chip->chip.npwm = VT8500_NR_PWMS;
|
chip->chip.npwm = VT8500_NR_PWMS;
|
||||||
|
|
||||||
chip->clk = devm_clk_get(&pdev->dev, NULL);
|
chip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
@ -240,15 +238,13 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
static int vt8500_pwm_remove(struct platform_device *pdev)
|
static int vt8500_pwm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct vt8500_chip *chip;
|
struct vt8500_chip *chip = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
chip = platform_get_drvdata(pdev);
|
pwmchip_remove(&chip->chip);
|
||||||
if (chip == NULL)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
clk_unprepare(chip->clk);
|
clk_unprepare(chip->clk);
|
||||||
|
|
||||||
return pwmchip_remove(&chip->chip);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver vt8500_pwm_driver = {
|
static struct platform_driver vt8500_pwm_driver = {
|
||||||
|
|
|
@ -54,12 +54,17 @@ enum {
|
||||||
* @duty_cycle: PWM duty cycle (in nanoseconds)
|
* @duty_cycle: PWM duty cycle (in nanoseconds)
|
||||||
* @polarity: PWM polarity
|
* @polarity: PWM polarity
|
||||||
* @enabled: PWM enabled status
|
* @enabled: PWM enabled status
|
||||||
|
* @usage_power: If set, the PWM driver is only required to maintain the power
|
||||||
|
* output but has more freedom regarding signal form.
|
||||||
|
* If supported, the signal can be optimized, for example to
|
||||||
|
* improve EMI by phase shifting individual channels.
|
||||||
*/
|
*/
|
||||||
struct pwm_state {
|
struct pwm_state {
|
||||||
u64 period;
|
u64 period;
|
||||||
u64 duty_cycle;
|
u64 duty_cycle;
|
||||||
enum pwm_polarity polarity;
|
enum pwm_polarity polarity;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
bool usage_power;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -188,6 +193,7 @@ static inline void pwm_init_state(const struct pwm_device *pwm,
|
||||||
state->period = args.period;
|
state->period = args.period;
|
||||||
state->polarity = args.polarity;
|
state->polarity = args.polarity;
|
||||||
state->duty_cycle = 0;
|
state->duty_cycle = 0;
|
||||||
|
state->usage_power = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -399,6 +405,9 @@ void *pwm_get_chip_data(struct pwm_device *pwm);
|
||||||
|
|
||||||
int pwmchip_add(struct pwm_chip *chip);
|
int pwmchip_add(struct pwm_chip *chip);
|
||||||
int pwmchip_remove(struct pwm_chip *chip);
|
int pwmchip_remove(struct pwm_chip *chip);
|
||||||
|
|
||||||
|
int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip);
|
||||||
|
|
||||||
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
||||||
unsigned int index,
|
unsigned int index,
|
||||||
const char *label);
|
const char *label);
|
||||||
|
@ -417,7 +426,6 @@ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
|
||||||
struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
|
struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
|
||||||
struct fwnode_handle *fwnode,
|
struct fwnode_handle *fwnode,
|
||||||
const char *con_id);
|
const char *con_id);
|
||||||
void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
|
|
||||||
#else
|
#else
|
||||||
static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
|
static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
|
||||||
{
|
{
|
||||||
|
@ -524,10 +532,6 @@ devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode,
|
||||||
{
|
{
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void pwm_apply_args(struct pwm_device *pwm)
|
static inline void pwm_apply_args(struct pwm_device *pwm)
|
||||||
|
@ -558,6 +562,7 @@ static inline void pwm_apply_args(struct pwm_device *pwm)
|
||||||
state.enabled = false;
|
state.enabled = false;
|
||||||
state.polarity = pwm->args.polarity;
|
state.polarity = pwm->args.polarity;
|
||||||
state.period = pwm->args.period;
|
state.period = pwm->args.period;
|
||||||
|
state.usage_power = false;
|
||||||
|
|
||||||
pwm_apply_state(pwm, &state);
|
pwm_apply_state(pwm, &state);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче