mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
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:
commit
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";
|
||||
};
|
64
Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml
Normal file
64
Documentation/devicetree/bindings/pwm/pwm-tiecap.yaml
Normal file
@ -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";
|
||||
};
|
65
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml
Normal file
65
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.yaml
Normal file
@ -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
|
||||
devm_pwm_get()
|
||||
devm_pwm_put()
|
||||
devm_of_pwm_get()
|
||||
devm_fwnode_pwm_get()
|
||||
|
||||
REGULATOR
|
||||
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
|
||||
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::
|
||||
|
||||
@ -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
|
||||
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
|
||||
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,
|
||||
};
|
||||
|
||||
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
|
||||
============
|
||||
|
||||
|
@ -126,8 +126,7 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
|
||||
/* check, whether the driver supports a third cell for flags */
|
||||
if (pc->of_pwm_n_cells < 3)
|
||||
if (pc->of_pwm_n_cells < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* 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.polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
if (pc->of_pwm_n_cells >= 3) {
|
||||
if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
}
|
||||
|
||||
return pwm;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!chip->dev || !chip->dev->of_node)
|
||||
return;
|
||||
|
||||
if (!chip->of_xlate) {
|
||||
chip->of_xlate = of_pwm_simple_xlate;
|
||||
chip->of_pwm_n_cells = 2;
|
||||
u32 pwm_cells;
|
||||
|
||||
if (of_property_read_u32(chip->dev->of_node, "#pwm-cells",
|
||||
&pwm_cells))
|
||||
pwm_cells = 2;
|
||||
|
||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->of_pwm_n_cells = pwm_cells;
|
||||
}
|
||||
|
||||
of_node_get(chip->dev->of_node);
|
||||
@ -324,22 +306,10 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
|
||||
*/
|
||||
int pwmchip_remove(struct pwm_chip *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
pwmchip_sysfs_unexport(chip);
|
||||
|
||||
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);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF))
|
||||
@ -347,12 +317,31 @@ int pwmchip_remove(struct pwm_chip *chip)
|
||||
|
||||
free_pwms(chip);
|
||||
|
||||
out:
|
||||
mutex_unlock(&pwm_lock);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
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: 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 &&
|
||||
state->duty_cycle == pwm->state.duty_cycle &&
|
||||
state->polarity == pwm->state.polarity &&
|
||||
state->enabled == pwm->state.enabled)
|
||||
state->enabled == pwm->state.enabled &&
|
||||
state->usage_power == pwm->state.usage_power)
|
||||
return 0;
|
||||
|
||||
if (chip->ops->apply) {
|
||||
@ -709,14 +699,14 @@ int pwm_adjust_config(struct pwm_device *pwm)
|
||||
}
|
||||
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;
|
||||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
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);
|
||||
return chip;
|
||||
}
|
||||
@ -795,7 +785,7 @@ struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
|
||||
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 (PTR_ERR(pc) != -EPROBE_DEFER)
|
||||
pr_err("%s(): PWM chip not found\n", __func__);
|
||||
@ -837,31 +827,9 @@ put:
|
||||
}
|
||||
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
|
||||
* @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
|
||||
* "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
|
||||
* 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);
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
struct pwm_device *pwm;
|
||||
struct fwnode_reference_args args;
|
||||
struct acpi_device *acpi;
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
@ -891,14 +857,10 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
acpi = to_acpi_device_node(args.fwnode);
|
||||
if (!acpi)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (args.nargs < 2)
|
||||
return ERR_PTR(-EPROTO);
|
||||
|
||||
chip = device_to_pwmchip(&acpi->dev);
|
||||
chip = fwnode_to_pwmchip(args.fwnode);
|
||||
if (IS_ERR(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)
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
|
||||
const char *dev_id = dev ? dev_name(dev) : NULL;
|
||||
struct pwm_device *pwm;
|
||||
struct pwm_chip *chip;
|
||||
@ -977,12 +939,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
||||
int err;
|
||||
|
||||
/* look up via DT first */
|
||||
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
|
||||
return of_pwm_get(dev, dev->of_node, con_id);
|
||||
if (is_of_node(fwnode))
|
||||
return of_pwm_get(dev, to_of_node(fwnode), con_id);
|
||||
|
||||
/* then lookup via ACPI */
|
||||
if (dev && is_acpi_node(dev->fwnode)) {
|
||||
pwm = acpi_pwm_get(dev->fwnode);
|
||||
if (is_acpi_node(fwnode)) {
|
||||
pwm = acpi_pwm_get(fwnode);
|
||||
if (!IS_ERR(pwm) || PTR_ERR(pwm) != -ENOENT)
|
||||
return pwm;
|
||||
}
|
||||
@ -1103,9 +1065,9 @@ out:
|
||||
}
|
||||
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 **ptr, *pwm;
|
||||
|
||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
struct pwm_device *pwm;
|
||||
int ret;
|
||||
|
||||
pwm = pwm_get(dev, con_id);
|
||||
if (!IS_ERR(pwm)) {
|
||||
*ptr = pwm;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
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,
|
||||
const char *con_id)
|
||||
{
|
||||
struct pwm_device **ptr, *pwm;
|
||||
|
||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
struct pwm_device *pwm;
|
||||
int ret;
|
||||
|
||||
pwm = of_pwm_get(dev, np, con_id);
|
||||
if (!IS_ERR(pwm)) {
|
||||
*ptr = pwm;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return pwm;
|
||||
}
|
||||
@ -1188,53 +1144,24 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
|
||||
struct fwnode_handle *fwnode,
|
||||
const char *con_id)
|
||||
{
|
||||
struct pwm_device **ptr, *pwm = ERR_PTR(-ENODEV);
|
||||
|
||||
ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
struct pwm_device *pwm = ERR_PTR(-ENODEV);
|
||||
int ret;
|
||||
|
||||
if (is_of_node(fwnode))
|
||||
pwm = of_pwm_get(dev, to_of_node(fwnode), con_id);
|
||||
else if (is_acpi_node(fwnode))
|
||||
pwm = acpi_pwm_get(fwnode);
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
if (!IS_ERR(pwm)) {
|
||||
*ptr = pwm;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return pwm;
|
||||
}
|
||||
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
|
||||
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",
|
||||
state.polarity ? "inverse" : "normal");
|
||||
|
||||
if (state.usage_power)
|
||||
seq_puts(s, " usage_power");
|
||||
|
||||
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.dev = dev;
|
||||
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);
|
||||
if (ret) {
|
||||
|
@ -469,8 +469,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
tcbpwm->chip.dev = &pdev->dev;
|
||||
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->channel = channel;
|
||||
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.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;
|
||||
|
||||
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.ops = &iproc_pwm_ops;
|
||||
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);
|
||||
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.ops = &kona_pwm_ops;
|
||||
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);
|
||||
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.ops = &bcm2835_pwm_ops;
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 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)
|
||||
@ -87,15 +87,15 @@ static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
kfree(channel);
|
||||
}
|
||||
|
||||
static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
||||
int duty_ns, int period_ns)
|
||||
static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
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;
|
||||
u32 value, duty, period;
|
||||
u64 cycles;
|
||||
|
||||
cycles = clk_get_rate(pwm->clk);
|
||||
cycles = clk_get_rate(bpc->clk);
|
||||
cycles *= period_ns;
|
||||
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);
|
||||
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)
|
||||
value |= BERLIN_PWM_PRESCALE_4096;
|
||||
else
|
||||
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(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT);
|
||||
berlin_pwm_writel(bpc, pwm->hwpwm, duty, BERLIN_PWM_DUTY);
|
||||
berlin_pwm_writel(bpc, pwm->hwpwm, period, BERLIN_PWM_TCNT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int berlin_pwm_set_polarity(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm_dev,
|
||||
struct pwm_device *pwm,
|
||||
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;
|
||||
|
||||
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)
|
||||
value &= ~BERLIN_PWM_INVERT_POLARITY;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
|
||||
berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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 = {
|
||||
.request = berlin_pwm_request,
|
||||
.free = berlin_pwm_free,
|
||||
.config = berlin_pwm_config,
|
||||
.set_polarity = berlin_pwm_set_polarity,
|
||||
.enable = berlin_pwm_enable,
|
||||
.disable = berlin_pwm_disable,
|
||||
.apply = berlin_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -185,99 +218,97 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match);
|
||||
|
||||
static int berlin_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct berlin_pwm_chip *pwm;
|
||||
struct berlin_pwm_chip *bpc;
|
||||
int ret;
|
||||
|
||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
||||
if (!pwm)
|
||||
bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL);
|
||||
if (!bpc)
|
||||
return -ENOMEM;
|
||||
|
||||
pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pwm->base))
|
||||
return PTR_ERR(pwm->base);
|
||||
bpc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(bpc->base))
|
||||
return PTR_ERR(bpc->base);
|
||||
|
||||
pwm->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwm->clk))
|
||||
return PTR_ERR(pwm->clk);
|
||||
bpc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(bpc->clk))
|
||||
return PTR_ERR(bpc->clk);
|
||||
|
||||
ret = clk_prepare_enable(pwm->clk);
|
||||
ret = clk_prepare_enable(bpc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &berlin_pwm_ops;
|
||||
pwm->chip.npwm = 4;
|
||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pwm->chip.of_pwm_n_cells = 3;
|
||||
bpc->chip.dev = &pdev->dev;
|
||||
bpc->chip.ops = &berlin_pwm_ops;
|
||||
bpc->chip.npwm = 4;
|
||||
|
||||
ret = pwmchip_add(&pwm->chip);
|
||||
ret = pwmchip_add(&bpc->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
clk_disable_unprepare(pwm->clk);
|
||||
clk_disable_unprepare(bpc->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pwm);
|
||||
platform_set_drvdata(pdev, bpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int berlin_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev);
|
||||
|
||||
ret = pwmchip_remove(&pwm->chip);
|
||||
clk_disable_unprepare(pwm->clk);
|
||||
pwmchip_remove(&bpc->chip);
|
||||
|
||||
return ret;
|
||||
clk_disable_unprepare(bpc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
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;
|
||||
|
||||
for (i = 0; i < pwm->chip.npwm; i++) {
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
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)
|
||||
continue;
|
||||
|
||||
channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE);
|
||||
channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL);
|
||||
channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY);
|
||||
channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT);
|
||||
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
|
||||
channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL);
|
||||
channel->duty = berlin_pwm_readl(bpc, i, BERLIN_PWM_DUTY);
|
||||
channel->tcnt = berlin_pwm_readl(bpc, i, BERLIN_PWM_TCNT);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(pwm->clk);
|
||||
clk_disable_unprepare(bpc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(pwm->clk);
|
||||
ret = clk_prepare_enable(bpc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < pwm->chip.npwm; i++) {
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
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)
|
||||
continue;
|
||||
|
||||
berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
||||
berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY);
|
||||
berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT);
|
||||
berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE);
|
||||
berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
||||
berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY);
|
||||
berlin_pwm_writel(bpc, i, channel->tcnt, BERLIN_PWM_TCNT);
|
||||
berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_ENABLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -134,16 +134,7 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
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);
|
||||
return devm_pwmchip_add(&pdev->dev, &priv->chip);
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
.probe = clps711x_pwm_probe,
|
||||
.remove = clps711x_pwm_remove,
|
||||
};
|
||||
module_platform_driver(clps711x_pwm_driver);
|
||||
|
||||
|
@ -173,21 +173,11 @@ static int crystalcove_pwm_probe(struct platform_device *pdev)
|
||||
/* get the PMIC regmap */
|
||||
pwm->regmap = pmic->regmap;
|
||||
|
||||
platform_set_drvdata(pdev, pwm);
|
||||
|
||||
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);
|
||||
return devm_pwmchip_add(&pdev->dev, &pwm->chip);
|
||||
}
|
||||
|
||||
static struct platform_driver crystalcove_pwm_driver = {
|
||||
.probe = crystalcove_pwm_probe,
|
||||
.remove = crystalcove_pwm_remove,
|
||||
.driver = {
|
||||
.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);
|
||||
}
|
||||
|
||||
static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int ret;
|
||||
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;
|
||||
int ret = 0;
|
||||
bool enabled = state->enabled;
|
||||
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (enabled) {
|
||||
writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
||||
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)
|
||||
return ret;
|
||||
}
|
||||
|
||||
c = clk_get_rate(ep93xx_pwm->clk);
|
||||
c *= period_ns;
|
||||
do_div(c, 1000000000);
|
||||
period_cycles = c;
|
||||
if (!enabled) {
|
||||
ret = clk_prepare_enable(ep93xx_pwm->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c = period_cycles;
|
||||
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;
|
||||
writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.request = ep93xx_pwm_request,
|
||||
.free = ep93xx_pwm_free,
|
||||
.config = ep93xx_pwm_config,
|
||||
.set_polarity = ep93xx_pwm_polarity,
|
||||
.enable = ep93xx_pwm_enable,
|
||||
.disable = ep93xx_pwm_disable,
|
||||
.apply = ep93xx_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -451,8 +451,6 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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.dev = &pdev->dev;
|
||||
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->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);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(chip->dev);
|
||||
ret = pm_runtime_resume_and_get(chip->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -363,8 +363,6 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||
|
||||
tpm->chip.dev = &pdev->dev;
|
||||
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 */
|
||||
val = readl(tpm->base + PWM_IMX_TPM_PARAM);
|
||||
|
@ -141,8 +141,6 @@ static int pwm_imx1_probe(struct platform_device *pdev)
|
||||
if (!imx)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, imx);
|
||||
|
||||
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_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))
|
||||
return PTR_ERR(imx->mmio_base);
|
||||
|
||||
return pwmchip_add(&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);
|
||||
return devm_pwmchip_add(&pdev->dev, &imx->chip);
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
.probe = pwm_imx1_probe,
|
||||
.remove = pwm_imx1_remove,
|
||||
};
|
||||
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.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);
|
||||
if (IS_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.ops = &jz4740_pwm_ops;
|
||||
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);
|
||||
|
||||
|
@ -371,8 +371,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
lpc18xx_pwm->chip.dev = &pdev->dev;
|
||||
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
pwm_lpss_remove(lpwm);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return pwm_lpss_remove(lpwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.npwm = info->npwm;
|
||||
|
||||
ret = pwmchip_add(&lpwm->chip);
|
||||
ret = devm_pwmchip_add(dev, &lpwm->chip);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add PWM chip: %d\n", 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);
|
||||
|
||||
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_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||
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,
|
||||
const struct pwm_lpss_boardinfo *info);
|
||||
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
|
||||
|
||||
#endif /* __PWM_LPSS_H */
|
||||
|
@ -551,8 +551,6 @@ static int meson_pwm_probe(struct platform_device *pdev)
|
||||
meson->chip.dev = &pdev->dev;
|
||||
meson->chip.ops = &meson_pwm_ops;
|
||||
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);
|
||||
|
||||
@ -560,31 +558,21 @@ static int meson_pwm_probe(struct platform_device *pdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = pwmchip_add(&meson->chip);
|
||||
err = devm_pwmchip_add(&pdev->dev, &meson->chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, meson);
|
||||
|
||||
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 = {
|
||||
.driver = {
|
||||
.name = "meson-pwm",
|
||||
.of_match_table = meson_pwm_matches,
|
||||
},
|
||||
.probe = meson_pwm_probe,
|
||||
.remove = meson_pwm_remove,
|
||||
};
|
||||
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.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);
|
||||
if (ret < 0) {
|
||||
|
@ -404,8 +404,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
omap->chip.dev = &pdev->dev;
|
||||
omap->chip.ops = &pwm_omap_dmtimer_ops;
|
||||
omap->chip.npwm = 1;
|
||||
omap->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
omap->chip.of_pwm_n_cells = 3;
|
||||
|
||||
mutex_init(&omap->mutex);
|
||||
|
||||
|
@ -23,11 +23,11 @@
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
/*
|
||||
* Because the PCA9685 has only one prescaler per chip, changing the period of
|
||||
* one channel affects the period of all 16 PWM outputs!
|
||||
* However, the ratio between each configured duty cycle and the chip-wide
|
||||
* period remains constant, because the OFF time is set in proportion to the
|
||||
* counter range.
|
||||
* Because the PCA9685 has only one prescaler per chip, only the first channel
|
||||
* that is enabled is allowed to change the prescale register.
|
||||
* PWM channels requested afterwards must use a period that results in the same
|
||||
* prescale setting as the one set by the first requested channel.
|
||||
* GPIOs do not count as enabled PWMs as they are not using the prescaler.
|
||||
*/
|
||||
|
||||
#define PCA9685_MODE1 0x00
|
||||
@ -78,8 +78,9 @@
|
||||
struct pca9685 {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||
struct mutex lock;
|
||||
DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||
struct gpio_chip gpio;
|
||||
DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
|
||||
#endif
|
||||
@ -90,51 +91,120 @@ static inline struct pca9685 *to_pca(struct pwm_chip *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%) */
|
||||
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) {
|
||||
/* 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) {
|
||||
/* Set the full ON bit and clear the full OFF bit */
|
||||
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
|
||||
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
|
||||
} else {
|
||||
/* 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);
|
||||
pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
|
||||
pca9685_write_reg(pca, REG_OFF_H(channel), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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)) {
|
||||
/* HW does not support reading state of "all LEDs" channel */
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, LED_N_OFF_H(channel), &off_h);
|
||||
if (off_h & LED_FULL) {
|
||||
pca9685_read_reg(pca, LED_N_OFF_H(channel), &off);
|
||||
if (off & LED_FULL) {
|
||||
/* Full OFF bit is set */
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, LED_N_ON_H(channel), &val);
|
||||
if (val & LED_FULL) {
|
||||
pca9685_read_reg(pca, LED_N_ON_H(channel), &on);
|
||||
if (on & LED_FULL) {
|
||||
/* Full ON bit is set */
|
||||
return PCA9685_COUNTER_RANGE;
|
||||
}
|
||||
|
||||
if (regmap_read(pca->regmap, LED_N_OFF_L(channel), &val)) {
|
||||
/* Reset val to 0 in case reading LED_N_OFF_L failed */
|
||||
pca9685_read_reg(pca, LED_N_OFF_L(channel), &val);
|
||||
off = ((off & 0xf) << 8) | (val & 0xff);
|
||||
if (!pwm->state.usage_power)
|
||||
return off;
|
||||
|
||||
/* Read ON register to calculate duty cycle of staggered output */
|
||||
if (pca9685_read_reg(pca, LED_N_ON_L(channel), &val)) {
|
||||
/* Reset val to 0 in case reading LED_N_ON_L failed */
|
||||
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)
|
||||
@ -240,8 +310,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
|
||||
{
|
||||
struct device *dev = pca->chip.dev;
|
||||
|
||||
mutex_init(&pca->lock);
|
||||
|
||||
pca->gpio.label = dev_name(dev);
|
||||
pca->gpio.parent = dev;
|
||||
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)
|
||||
{
|
||||
regmap_update_bits(pca->regmap, PCA9685_MODE1,
|
||||
MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
|
||||
struct device *dev = pca->chip.dev;
|
||||
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) {
|
||||
/* Wait 500us for the oscillator to be back up */
|
||||
udelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned long long duty, prescale;
|
||||
@ -307,8 +382,14 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
|
||||
pca9685_read_reg(pca, PCA9685_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
|
||||
* 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);
|
||||
|
||||
/* Change the chip-wide output frequency */
|
||||
regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
|
||||
pca9685_write_reg(pca, PCA9685_PRESCALE, prescale);
|
||||
|
||||
/* Wake the chip up */
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
|
||||
/* 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.
|
||||
* 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))
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
mutex_lock(&pca->lock);
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||
clear_bit(pwm->hwpwm, pca->pwms_enabled);
|
||||
mutex_unlock(&pca->lock);
|
||||
|
||||
pm_runtime_put(chip->dev);
|
||||
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);
|
||||
|
||||
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"))
|
||||
reg |= MODE2_INVRT;
|
||||
@ -434,16 +550,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
||||
else
|
||||
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 */
|
||||
regmap_read(pca->regmap, PCA9685_MODE1, ®);
|
||||
pca9685_read_reg(pca, PCA9685_MODE1, ®);
|
||||
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 */
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
|
||||
/* Reset OFF/ON registers to POR default */
|
||||
pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, 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;
|
||||
/* 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)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct pxa_pwm_chip *pwm;
|
||||
struct pxa_pwm_chip *pc;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && id == NULL)
|
||||
@ -174,46 +174,44 @@ static int pwm_probe(struct platform_device *pdev)
|
||||
if (id == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
|
||||
if (pwm == NULL)
|
||||
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
if (pc == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pwm->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwm->clk))
|
||||
return PTR_ERR(pwm->clk);
|
||||
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pc->clk))
|
||||
return PTR_ERR(pc->clk);
|
||||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &pxa_pwm_ops;
|
||||
pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &pxa_pwm_ops;
|
||||
pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF)) {
|
||||
pwm->chip.of_xlate = pxa_pwm_of_xlate;
|
||||
pwm->chip.of_pwm_n_cells = 1;
|
||||
pc->chip.of_xlate = pxa_pwm_of_xlate;
|
||||
pc->chip.of_pwm_n_cells = 1;
|
||||
}
|
||||
|
||||
pwm->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pwm->mmio_base))
|
||||
return PTR_ERR(pwm->mmio_base);
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
return PTR_ERR(pc->mmio_base);
|
||||
|
||||
ret = pwmchip_add(&pwm->chip);
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pwm);
|
||||
platform_set_drvdata(pdev, pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa_pwm_chip *chip;
|
||||
struct pxa_pwm_chip *pc;
|
||||
|
||||
chip = platform_get_drvdata(pdev);
|
||||
if (chip == NULL)
|
||||
return -ENODEV;
|
||||
pc = platform_get_drvdata(pdev);
|
||||
|
||||
return pwmchip_remove(&chip->chip);
|
||||
return pwmchip_remove(&pc->chip);
|
||||
}
|
||||
|
||||
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.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;
|
||||
|
||||
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.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;
|
||||
ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->chip.of_pwm_n_cells = 3;
|
||||
} else {
|
||||
if (!pdev->dev.platform_data) {
|
||||
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->dev = dev;
|
||||
chip->ops = &pwm_sifive_ops;
|
||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->of_pwm_n_cells = 3;
|
||||
chip->npwm = 4;
|
||||
|
||||
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,
|
||||
int duty_ns, int period_ns)
|
||||
u64 duty_ns, u64 period_ns)
|
||||
{
|
||||
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
|
||||
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);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.config = spear_pwm_config,
|
||||
.enable = spear_pwm_enable,
|
||||
.disable = spear_pwm_disable,
|
||||
.apply = spear_pwm_apply,
|
||||
.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)
|
||||
{
|
||||
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PWM; i++)
|
||||
pwm_disable(&pc->chip.pwms[i]);
|
||||
pwmchip_remove(&pc->chip);
|
||||
|
||||
/* clk was prepared in probe, hence unprepare it here */
|
||||
clk_unprepare(pc->clk);
|
||||
return pwmchip_remove(&pc->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return pwmchip_remove(&spc->chip);
|
||||
pwmchip_remove(&spc->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.ops = &stm32_pwm_lp_ops;
|
||||
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);
|
||||
if (ret < 0)
|
||||
|
@ -621,8 +621,6 @@ static int stm32_pwm_probe(struct platform_device *pdev)
|
||||
priv->regmap = ddata->regmap;
|
||||
priv->clk = ddata->clk;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -460,8 +460,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &sun4i_pwm_ops;
|
||||
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);
|
||||
|
||||
|
@ -300,32 +300,12 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
||||
static int tegra_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
if (WARN_ON(!pc))
|
||||
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);
|
||||
}
|
||||
pwmchip_remove(&pc->chip);
|
||||
|
||||
reset_control_assert(pc->rst);
|
||||
clk_disable_unprepare(pc->clk);
|
||||
|
||||
return pwmchip_remove(&pc->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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
|
||||
*/
|
||||
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);
|
||||
u32 period_cycles, duty_cycles;
|
||||
unsigned long long c;
|
||||
u16 value;
|
||||
|
||||
if (period_ns > NSEC_PER_SEC)
|
||||
return -ERANGE;
|
||||
|
||||
c = pc->clk_rate;
|
||||
c = c * period_ns;
|
||||
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);
|
||||
|
||||
if (!pwm_is_enabled(pwm)) {
|
||||
if (!enabled) {
|
||||
/* Update active registers if not running */
|
||||
writel(duty_cycles, pc->mmio_base + CAP2);
|
||||
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);
|
||||
}
|
||||
|
||||
if (!pwm_is_enabled(pwm)) {
|
||||
if (!enabled) {
|
||||
value = readw(pc->mmio_base + ECCTL2);
|
||||
/* Disable APWM mode to put APWM output Low */
|
||||
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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
dev_warn(chip->dev, "Removing PWM device without disabling\n");
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
int err;
|
||||
int enabled = pwm->state.enabled;
|
||||
|
||||
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 = {
|
||||
.free = ecap_pwm_free,
|
||||
.config = ecap_pwm_config,
|
||||
.set_polarity = ecap_pwm_set_polarity,
|
||||
.enable = ecap_pwm_enable,
|
||||
.disable = ecap_pwm_disable,
|
||||
.apply = ecap_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -224,8 +250,6 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
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->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.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->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;
|
||||
|
||||
/*
|
||||
* PWMC controls a divider that divides the input clk by a
|
||||
* power of two between 1 and 8. As a smaller divider yields
|
||||
* higher precision, pick the smallest possible one.
|
||||
* PWMC controls a divider that divides the input clk by a power of two
|
||||
* between 1 and 8. As a smaller divider yields higher precision, pick
|
||||
* the smallest possible one. As period is at most 0xffff << 3, pwmc0 is
|
||||
* in the intended range [0..3].
|
||||
*/
|
||||
if (period > 0xffff) {
|
||||
pwmc0 = ilog2(period >> 16);
|
||||
if (WARN_ON(pwmc0 > 3))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
pwmc0 = 0;
|
||||
}
|
||||
pwmc0 = fls(period >> 16);
|
||||
if (WARN_ON(pwmc0 > 3))
|
||||
return -EINVAL;
|
||||
|
||||
period >>= pwmc0;
|
||||
duty_cycle >>= pwmc0;
|
||||
|
@ -207,8 +207,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
chip->chip.dev = &pdev->dev;
|
||||
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->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)
|
||||
{
|
||||
struct vt8500_chip *chip;
|
||||
struct vt8500_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
chip = platform_get_drvdata(pdev);
|
||||
if (chip == NULL)
|
||||
return -ENODEV;
|
||||
pwmchip_remove(&chip->chip);
|
||||
|
||||
clk_unprepare(chip->clk);
|
||||
|
||||
return pwmchip_remove(&chip->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vt8500_pwm_driver = {
|
||||
|
@ -54,12 +54,17 @@ enum {
|
||||
* @duty_cycle: PWM duty cycle (in nanoseconds)
|
||||
* @polarity: PWM polarity
|
||||
* @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 {
|
||||
u64 period;
|
||||
u64 duty_cycle;
|
||||
enum pwm_polarity polarity;
|
||||
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->polarity = args.polarity;
|
||||
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_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,
|
||||
unsigned int index,
|
||||
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 fwnode_handle *fwnode,
|
||||
const char *con_id);
|
||||
void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
|
||||
#else
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
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.polarity = pwm->args.polarity;
|
||||
state.period = pwm->args.period;
|
||||
state.usage_power = false;
|
||||
|
||||
pwm_apply_state(pwm, &state);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user