Commit 38f7d2da authored by Linus Torvalds's avatar Linus Torvalds

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

Merge tag 'pwm/for-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "This release cycle's changes include mostly updates and cleanups to
  existing drivers along with a few cleanups to the core, documentation
  and device tree bindings"

* tag 'pwm/for-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: cros-ec: Fix transposed param settings
  pwm: meson: Improve PWM calculation precision
  dt-bindings: pwm: meson: Add compatible for gxbb ao PWMs
  pwm: meson: Add compatible for the gxbb ao PWMs
  pwm: sun4i: Drop legacy callbacks
  pwm: sun4i: Switch to atomic PWM
  pwm: sun4i: Improve hardware read out
  pwm: hibvt: Constify hibvt_pwm_ops
  pwm: Silently error out on EPROBE_DEFER
  pwm: Standardize document format
  pwm: bfin: Remove unneeded error message
  dt-bindings: pwm: Update STM32 timers clock names
  dt-bindings: pwm: Add R-Car M3-W device tree bindings
  pwm: tegra: Set maximum pwm clock source per SoC tapeout
parents dc087d1e 5ec8c48a
...@@ -2,7 +2,9 @@ Amlogic Meson PWM Controller ...@@ -2,7 +2,9 @@ Amlogic Meson PWM Controller
============================ ============================
Required properties: Required properties:
- compatible: Shall contain "amlogic,meson8b-pwm" or "amlogic,meson-gxbb-pwm". - compatible: Shall contain "amlogic,meson8b-pwm"
or "amlogic,meson-gxbb-pwm"
or "amlogic,meson-gxbb-ao-pwm"
- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
the cells format. the cells format.
......
...@@ -24,7 +24,7 @@ Example: ...@@ -24,7 +24,7 @@ Example:
compatible = "st,stm32-timers"; compatible = "st,stm32-timers";
reg = <0x40010000 0x400>; reg = <0x40010000 0x400>;
clocks = <&rcc 0 160>; clocks = <&rcc 0 160>;
clock-names = "clk_int"; clock-names = "int";
pwm { pwm {
compatible = "st,stm32-pwm"; compatible = "st,stm32-pwm";
......
...@@ -8,6 +8,7 @@ Required Properties: ...@@ -8,6 +8,7 @@ Required Properties:
- "renesas,pwm-r8a7791": for R-Car M2-W - "renesas,pwm-r8a7791": for R-Car M2-W
- "renesas,pwm-r8a7794": for R-Car E2 - "renesas,pwm-r8a7794": for R-Car E2
- "renesas,pwm-r8a7795": for R-Car H3 - "renesas,pwm-r8a7795": for R-Car H3
- "renesas,pwm-r8a7796": for R-Car M3-W
- reg: base address and length of the registers block for the PWM. - reg: base address and length of the registers block for the PWM.
- #pwm-cells: should be 2. See pwm.txt in this directory for a description of - #pwm-cells: should be 2. See pwm.txt in this directory for a description of
the cells format. the cells format.
......
======================================
Pulse Width Modulation (PWM) interface Pulse Width Modulation (PWM) interface
======================================
This provides an overview about the Linux PWM interface This provides an overview about the Linux PWM interface
...@@ -16,7 +18,7 @@ Users of the legacy PWM API use unique IDs to refer to PWM devices. ...@@ -16,7 +18,7 @@ Users of the legacy PWM API use unique IDs to refer to PWM devices.
Instead of referring to a PWM device via its unique ID, board setup code Instead of referring to a PWM device via its unique ID, board setup code
should instead register a static mapping that can be used to match PWM should instead register a static mapping that can be used to match PWM
consumers to providers, as given in the following example: consumers to providers, as given in the following example::
static struct pwm_lookup board_pwm_lookup[] = { static struct pwm_lookup board_pwm_lookup[] = {
PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL, PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL,
...@@ -40,9 +42,9 @@ New users should use the pwm_get() function and pass to it the consumer ...@@ -40,9 +42,9 @@ 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 these functions, devm_pwm_get() and devm_pwm_put(), also exist.
After being requested, a PWM has to be configured using: After being requested, a PWM has to be configured using::
int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
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.
...@@ -72,11 +74,14 @@ interface is provided to use the PWMs from userspace. It is exposed at ...@@ -72,11 +74,14 @@ interface is provided to use the PWMs from userspace. It is exposed at
pwmchipN, where N is the base of the PWM chip. Inside the directory you pwmchipN, where N is the base of the PWM chip. Inside the directory you
will find: will find:
npwm - The number of PWM channels this chip supports (read-only). npwm
The number of PWM channels this chip supports (read-only).
export - Exports a PWM channel for use with sysfs (write-only). export
Exports a PWM channel for use with sysfs (write-only).
unexport - Unexports a PWM channel from sysfs (write-only). unexport
Unexports a PWM channel from sysfs (write-only).
The PWM channels are numbered using a per-chip index from 0 to npwm-1. The PWM channels are numbered using a per-chip index from 0 to npwm-1.
...@@ -84,21 +89,26 @@ When a PWM channel is exported a pwmX directory will be created in the ...@@ -84,21 +89,26 @@ When a PWM channel is exported a pwmX directory will be created in the
pwmchipN directory it is associated with, where X is the number of the pwmchipN directory it is associated with, where X is the number of the
channel that was exported. The following properties will then be available: channel that was exported. The following properties will then be available:
period - The total period of the PWM signal (read/write). period
The total period of the PWM signal (read/write).
Value is in nanoseconds and is the sum of the active and inactive Value is in nanoseconds and is the sum of the active and inactive
time of the PWM. time of the PWM.
duty_cycle - The active time of the PWM signal (read/write). duty_cycle
The active time of the PWM signal (read/write).
Value is in nanoseconds and must be less than the period. Value is in nanoseconds and must be less than the period.
polarity - Changes the polarity of the PWM signal (read/write). polarity
Changes the polarity of the PWM signal (read/write).
Writes to this property only work if the PWM chip supports changing Writes to this property only work if the PWM chip supports changing
the polarity. The polarity can only be changed if the PWM is not the polarity. The polarity can only be changed if the PWM is not
enabled. Value is the string "normal" or "inversed". enabled. Value is the string "normal" or "inversed".
enable - Enable/disable the PWM signal (read/write). enable
0 - disabled Enable/disable the PWM signal (read/write).
1 - enabled
- 0 - disabled
- 1 - enabled
Implementing a PWM driver Implementing a PWM driver
------------------------- -------------------------
......
...@@ -678,7 +678,9 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) ...@@ -678,7 +678,9 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
pc = of_node_to_pwmchip(args.np); pc = of_node_to_pwmchip(args.np);
if (IS_ERR(pc)) { if (IS_ERR(pc)) {
if (PTR_ERR(pc) != -EPROBE_DEFER)
pr_err("%s(): PWM chip not found\n", __func__); pr_err("%s(): PWM chip not found\n", __func__);
pwm = ERR_CAST(pc); pwm = ERR_CAST(pc);
goto put; goto put;
} }
......
...@@ -118,10 +118,8 @@ static int bfin_pwm_probe(struct platform_device *pdev) ...@@ -118,10 +118,8 @@ static int bfin_pwm_probe(struct platform_device *pdev)
int ret; int ret;
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
if (!pwm) { if (!pwm)
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM; return -ENOMEM;
}
platform_set_drvdata(pdev, pwm); platform_set_drvdata(pdev, pwm);
......
...@@ -75,8 +75,8 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index, ...@@ -75,8 +75,8 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index,
msg->version = 0; msg->version = 0;
msg->command = EC_CMD_PWM_GET_DUTY; msg->command = EC_CMD_PWM_GET_DUTY;
msg->insize = sizeof(*params); msg->insize = sizeof(*resp);
msg->outsize = sizeof(*resp); msg->outsize = sizeof(*params);
params->pwm_type = EC_PWM_TYPE_GENERIC; params->pwm_type = EC_PWM_TYPE_GENERIC;
params->index = index; params->index = index;
......
...@@ -165,7 +165,7 @@ static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -165,7 +165,7 @@ static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0; return 0;
} }
static struct pwm_ops hibvt_pwm_ops = { static const struct pwm_ops hibvt_pwm_ops = {
.get_state = hibvt_pwm_get_state, .get_state = hibvt_pwm_get_state,
.apply = hibvt_pwm_apply, .apply = hibvt_pwm_apply,
......
...@@ -103,6 +103,7 @@ struct meson_pwm_channel { ...@@ -103,6 +103,7 @@ struct meson_pwm_channel {
struct meson_pwm_data { struct meson_pwm_data {
const char * const *parent_names; const char * const *parent_names;
unsigned int num_parents;
}; };
struct meson_pwm { struct meson_pwm {
...@@ -162,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, ...@@ -162,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
unsigned int duty, unsigned int period) unsigned int duty, unsigned int period)
{ {
unsigned int pre_div, cnt, duty_cnt; unsigned int pre_div, cnt, duty_cnt;
unsigned long fin_freq = -1, fin_ns; unsigned long fin_freq = -1;
u64 fin_ps;
if (~(meson->inverter_mask >> id) & 0x1) if (~(meson->inverter_mask >> id) & 0x1)
duty = period - duty; duty = period - duty;
...@@ -178,13 +180,15 @@ static int meson_pwm_calc(struct meson_pwm *meson, ...@@ -178,13 +180,15 @@ static int meson_pwm_calc(struct meson_pwm *meson,
} }
dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
fin_ns = NSEC_PER_SEC / fin_freq; fin_ps = (u64)NSEC_PER_SEC * 1000;
do_div(fin_ps, fin_freq);
/* Calc pre_div with the period */ /* Calc pre_div with the period */
for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) {
cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1)); cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n", fin_ps * (pre_div + 1));
fin_ns, pre_div, cnt); dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n",
fin_ps, pre_div, cnt);
if (cnt <= 0xffff) if (cnt <= 0xffff)
break; break;
} }
...@@ -207,7 +211,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, ...@@ -207,7 +211,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
channel->lo = cnt; channel->lo = cnt;
} else { } else {
/* Then check is we can have the duty with the same pre_div */ /* Then check is we can have the duty with the same pre_div */
duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1)); duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
fin_ps * (pre_div + 1));
if (duty_cnt > 0xffff) { if (duty_cnt > 0xffff) {
dev_err(meson->chip.dev, "unable to get duty cycle\n"); dev_err(meson->chip.dev, "unable to get duty cycle\n");
return -EINVAL; return -EINVAL;
...@@ -381,6 +386,7 @@ static const char * const pwm_meson8b_parent_names[] = { ...@@ -381,6 +386,7 @@ static const char * const pwm_meson8b_parent_names[] = {
static const struct meson_pwm_data pwm_meson8b_data = { static const struct meson_pwm_data pwm_meson8b_data = {
.parent_names = pwm_meson8b_parent_names, .parent_names = pwm_meson8b_parent_names,
.num_parents = ARRAY_SIZE(pwm_meson8b_parent_names),
}; };
static const char * const pwm_gxbb_parent_names[] = { static const char * const pwm_gxbb_parent_names[] = {
...@@ -389,11 +395,35 @@ static const char * const pwm_gxbb_parent_names[] = { ...@@ -389,11 +395,35 @@ static const char * const pwm_gxbb_parent_names[] = {
static const struct meson_pwm_data pwm_gxbb_data = { static const struct meson_pwm_data pwm_gxbb_data = {
.parent_names = pwm_gxbb_parent_names, .parent_names = pwm_gxbb_parent_names,
.num_parents = ARRAY_SIZE(pwm_gxbb_parent_names),
};
/*
* Only the 2 first inputs of the GXBB AO PWMs are valid
* The last 2 are grounded
*/
static const char * const pwm_gxbb_ao_parent_names[] = {
"xtal", "clk81"
};
static const struct meson_pwm_data pwm_gxbb_ao_data = {
.parent_names = pwm_gxbb_ao_parent_names,
.num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_names),
}; };
static const struct of_device_id meson_pwm_matches[] = { static const struct of_device_id meson_pwm_matches[] = {
{ .compatible = "amlogic,meson8b-pwm", .data = &pwm_meson8b_data }, {
{ .compatible = "amlogic,meson-gxbb-pwm", .data = &pwm_gxbb_data }, .compatible = "amlogic,meson8b-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-gxbb-pwm",
.data = &pwm_gxbb_data
},
{
.compatible = "amlogic,meson-gxbb-ao-pwm",
.data = &pwm_gxbb_ao_data
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, meson_pwm_matches); MODULE_DEVICE_TABLE(of, meson_pwm_matches);
...@@ -417,7 +447,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, ...@@ -417,7 +447,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
init.ops = &clk_mux_ops; init.ops = &clk_mux_ops;
init.flags = CLK_IS_BASIC; init.flags = CLK_IS_BASIC;
init.parent_names = meson->data->parent_names; init.parent_names = meson->data->parent_names;
init.num_parents = 1 << MISC_CLK_SEL_WIDTH; init.num_parents = meson->data->num_parents;
channel->mux.reg = meson->base + REG_MISC_AB; channel->mux.reg = meson->base + REG_MISC_AB;
channel->mux.shift = mux_reg_shifts[i]; channel->mux.shift = mux_reg_shifts[i];
......
This diff is collapsed.
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
struct tegra_pwm_soc { struct tegra_pwm_soc {
unsigned int num_channels; unsigned int num_channels;
/* Maximum IP frequency for given SoCs */
unsigned long max_frequency;
}; };
struct tegra_pwm_chip { struct tegra_pwm_chip {
...@@ -201,7 +204,18 @@ static int tegra_pwm_probe(struct platform_device *pdev) ...@@ -201,7 +204,18 @@ static int tegra_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->clk)) if (IS_ERR(pwm->clk))
return PTR_ERR(pwm->clk); return PTR_ERR(pwm->clk);
/* Read PWM clock rate from source */ /* Set maximum frequency of the IP */
ret = clk_set_rate(pwm->clk, pwm->soc->max_frequency);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret);
return ret;
}
/*
* The requested and configured frequency may differ due to
* clock register resolutions. Get the configured frequency
* so that PWM period can be calculated more accurately.
*/
pwm->clk_rate = clk_get_rate(pwm->clk); pwm->clk_rate = clk_get_rate(pwm->clk);
pwm->rst = devm_reset_control_get(&pdev->dev, "pwm"); pwm->rst = devm_reset_control_get(&pdev->dev, "pwm");
...@@ -273,10 +287,12 @@ static int tegra_pwm_resume(struct device *dev) ...@@ -273,10 +287,12 @@ static int tegra_pwm_resume(struct device *dev)
static const struct tegra_pwm_soc tegra20_pwm_soc = { static const struct tegra_pwm_soc tegra20_pwm_soc = {
.num_channels = 4, .num_channels = 4,
.max_frequency = 48000000UL,
}; };
static const struct tegra_pwm_soc tegra186_pwm_soc = { static const struct tegra_pwm_soc tegra186_pwm_soc = {
.num_channels = 1, .num_channels = 1,
.max_frequency = 102000000UL,
}; };
static const struct of_device_id tegra_pwm_of_match[] = { static const struct of_device_id tegra_pwm_of_match[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment