Commit 9d81e2d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pwm/for-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux

Pull pwm updates from Uwe Kleine-König:
 "Apart for the normal updates for dt bindings, cleanups and support for
  new device variants to existing drivers this completes the conversion
  to pwmchip_alloc() which was started in the v6.9 development cycle.

  Using pwmchip_alloc() is a precondition to the character device
  support which allows easier and faster access to PWM devices. However
  there are some issues I want to clean up before including it in
  mainline, so this isn't contained here despite it was in next for some
  time.

  Thanks to Alexandre Mergnat, Binbin Zhou, Dmitry Rokosov, George
  Stark, Jerome Brunet and Varshini Rajendran for their contributions.
  Further thanks go to AngeloGioacchino Del Regno, Conor Dooley, David
  Lechner, Fabrice Gasnier, Florian Fainelli, Guenter Roeck, Gustavo A.
  R. Silva, Krzysztof Kozlowski and Rob Herring for valuable patch
  review"

* tag 'pwm/for-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux: (34 commits)
  pwm: pca9685: Drop explicit initialization of struct i2c_device_id::driver_data to 0
  dt-bindings: pwm: snps,dw-apb-timers: Do not require pwm-cells twice
  dt-bindings: pwm: mediatek,pwm-disp: Do not require pwm-cells twice
  dt-bindings: pwm: mediatek,mt2712: Do not require pwm-cells twice
  dt-bindings: pwm: marvell,pxa: Do not require pwm-cells twice
  dt-bindings: pwm: google,cros-ec: Do not require pwm-cells twice
  dt-bindings: pwm: bcm2835: Do not require pwm-cells twice
  pwm: meson: Use mul_u64_u64_div_u64() for frequency calculating
  pwm: meson: Add check for error from clk_round_rate()
  pwm: meson: Drop unneeded check in .get_state()
  dt-bindings: pwm: mediatek,pwm-disp: add compatible for mt8365 SoC
  pwm: meson: Add generic compatible for meson8 to sm1
  pwm: bcm2835: Drop open coded variant of devm_clk_rate_exclusive_get()
  pwm: bcm2835: Introduce a local variable for &pdev->dev
  pwm: stm32: Calculate prescaler with a division instead of a loop
  pwm: stm32: Fix for settings using period > UINT32_MAX
  pwm: stm32: Improve precision of calculation in .apply()
  pwm: stm32: Add error messages in .probe()'s error paths
  pwm: Make pwmchip_[sg]et_drvdata() a wrapper around dev_set_drvdata()
  pwm: Don't check pointer for being non-NULL after use
  ...
parents 00fddaf5 4817118f
......@@ -25,6 +25,9 @@ properties:
- items:
- const: microchip,sama7g5-pwm
- const: atmel,sama5d2-pwm
- items:
- const: microchip,sam9x7-pwm
- const: microchip,sam9x60-pwm
reg:
maxItems: 1
......
......@@ -35,7 +35,6 @@ properties:
required:
- compatible
- '#pwm-cells'
additionalProperties: false
......
......@@ -34,7 +34,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
additionalProperties: false
......
......@@ -66,7 +66,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
- clock-names
......
......@@ -31,6 +31,7 @@ properties:
- mediatek,mt8188-disp-pwm
- mediatek,mt8192-disp-pwm
- mediatek,mt8195-disp-pwm
- mediatek,mt8365-disp-pwm
- const: mediatek,mt8183-disp-pwm
reg:
......@@ -58,7 +59,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
- clock-names
......
......@@ -29,7 +29,6 @@ required:
- compatible
- reg
- clocks
- "#pwm-cells"
additionalProperties: false
......
......@@ -51,7 +51,6 @@ properties:
required:
- compatible
- reg
- "#pwm-cells"
- clocks
- clock-names
......
......@@ -136,7 +136,6 @@ struct aspeed_pwm_tach_data {
struct clk *clk;
struct reset_control *reset;
unsigned long clk_rate;
struct pwm_chip chip;
bool tach_present[TACH_ASPEED_NR_TACHS];
u32 tach_divisor;
};
......@@ -144,7 +143,7 @@ struct aspeed_pwm_tach_data {
static inline struct aspeed_pwm_tach_data *
aspeed_pwm_chip_to_data(struct pwm_chip *chip)
{
return container_of(chip, struct aspeed_pwm_tach_data, chip);
return pwmchip_get_drvdata(chip);
}
static int aspeed_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
......@@ -195,7 +194,7 @@ static int aspeed_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
expect_period = div64_u64(ULLONG_MAX, (u64)priv->clk_rate);
expect_period = min(expect_period, state->period);
dev_dbg(chip->dev, "expect period: %lldns, duty_cycle: %lldns",
dev_dbg(pwmchip_parent(chip), "expect period: %lldns, duty_cycle: %lldns",
expect_period, state->duty_cycle);
/*
* Pick the smallest value for div_h so that div_l can be the biggest
......@@ -218,12 +217,12 @@ static int aspeed_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (div_l > 255)
div_l = 255;
dev_dbg(chip->dev, "clk source: %ld div_h %lld, div_l : %lld\n",
dev_dbg(pwmchip_parent(chip), "clk source: %ld div_h %lld, div_l : %lld\n",
priv->clk_rate, div_h, div_l);
/* duty_pt = duty_cycle * (PERIOD + 1) / period */
duty_pt = div64_u64(state->duty_cycle * priv->clk_rate,
(u64)NSEC_PER_SEC * (div_l + 1) << div_h);
dev_dbg(chip->dev, "duty_cycle = %lld, duty_pt = %d\n",
dev_dbg(pwmchip_parent(chip), "duty_cycle = %lld, duty_pt = %d\n",
state->duty_cycle, duty_pt);
/*
......@@ -459,6 +458,7 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev)
int ret;
struct device_node *child;
struct aspeed_pwm_tach_data *priv;
struct pwm_chip *chip;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
......@@ -487,11 +487,14 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev)
if (ret)
return ret;
priv->chip.dev = dev;
priv->chip.ops = &aspeed_pwm_ops;
priv->chip.npwm = PWM_ASPEED_NR_PWMS;
chip = devm_pwmchip_alloc(dev, PWM_ASPEED_NR_PWMS, 0);
if (IS_ERR(chip))
return PTR_ERR(chip);
ret = devm_pwmchip_add(dev, &priv->chip);
pwmchip_set_drvdata(chip, priv);
chip->ops = &aspeed_pwm_ops;
ret = devm_pwmchip_add(dev, chip);
if (ret)
return dev_err_probe(dev, ret, "Failed to add PWM chip\n");
......
......@@ -29,10 +29,6 @@ menuconfig PWM
if PWM
config PWM_SYSFS
bool
default y if SYSFS
config PWM_DEBUG
bool "PWM lowlevel drivers additional checks and debug messages"
depends on DEBUG_KERNEL
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_SYSFS) += sysfs.o
obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
obj-$(CONFIG_PWM_APPLE) += pwm-apple.o
obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
......
This diff is collapsed.
......@@ -124,20 +124,14 @@ static const struct pwm_ops bcm2835_pwm_ops = {
.apply = bcm2835_pwm_apply,
};
static void devm_clk_rate_exclusive_put(void *data)
{
struct clk *clk = data;
clk_rate_exclusive_put(clk);
}
static int bcm2835_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pwm_chip *chip;
struct bcm2835_pwm *pc;
int ret;
chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*pc));
chip = devm_pwmchip_alloc(dev, 2, sizeof(*pc));
if (IS_ERR(chip))
return PTR_ERR(chip);
pc = to_bcm2835_pwm(chip);
......@@ -146,24 +140,19 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pc->base))
return PTR_ERR(pc->base);
pc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
pc->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(pc->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
return dev_err_probe(dev, PTR_ERR(pc->clk),
"clock not found\n");
ret = clk_rate_exclusive_get(pc->clk);
ret = devm_clk_rate_exclusive_get(dev, pc->clk);
if (ret)
return dev_err_probe(&pdev->dev, ret,
return dev_err_probe(dev, ret,
"fail to get exclusive rate\n");
ret = devm_add_action_or_reset(&pdev->dev, devm_clk_rate_exclusive_put,
pc->clk);
if (ret)
return ret;
pc->rate = clk_get_rate(pc->clk);
if (!pc->rate)
return dev_err_probe(&pdev->dev, -EINVAL,
return dev_err_probe(dev, -EINVAL,
"failed to get clock rate\n");
chip->ops = &bcm2835_pwm_ops;
......@@ -171,10 +160,9 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pc);
ret = devm_pwmchip_add(&pdev->dev, chip);
ret = devm_pwmchip_add(dev, chip);
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"failed to add pwmchip\n");
return dev_err_probe(dev, ret, "failed to add pwmchip\n");
return 0;
}
......
......@@ -98,6 +98,7 @@ struct meson_pwm_channel {
struct meson_pwm_data {
const char *const parent_names[MESON_NUM_MUX_PARENTS];
int (*channels_init)(struct pwm_chip *chip);
};
struct meson_pwm {
......@@ -147,7 +148,7 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
struct meson_pwm *meson = to_meson_pwm(chip);
struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
unsigned int cnt, duty_cnt;
unsigned long fin_freq;
long fin_freq;
u64 duty, period, freq;
duty = state->duty_cycle;
......@@ -167,14 +168,15 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
freq = ULONG_MAX;
fin_freq = clk_round_rate(channel->clk, freq);
if (fin_freq == 0) {
dev_err(pwmchip_parent(chip), "invalid source clock frequency\n");
return -EINVAL;
if (fin_freq <= 0) {
dev_err(pwmchip_parent(chip),
"invalid source clock frequency %llu\n", freq);
return fin_freq ? fin_freq : -EINVAL;
}
dev_dbg(pwmchip_parent(chip), "fin_freq: %lu Hz\n", fin_freq);
dev_dbg(pwmchip_parent(chip), "fin_freq: %ld Hz\n", fin_freq);
cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
cnt = mul_u64_u64_div_u64(fin_freq, period, NSEC_PER_SEC);
if (cnt > 0xffff) {
dev_err(pwmchip_parent(chip), "unable to get period cnt\n");
return -EINVAL;
......@@ -189,7 +191,7 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
channel->hi = 0;
channel->lo = cnt;
} else {
duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
duty_cnt = mul_u64_u64_div_u64(fin_freq, duty, NSEC_PER_SEC);
dev_dbg(pwmchip_parent(chip), "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
......@@ -310,9 +312,6 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct meson_pwm_channel *channel;
u32 value;
if (!state)
return 0;
channel = &meson->channels[pwm->hwpwm];
channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
......@@ -338,86 +337,16 @@ static const struct pwm_ops meson_pwm_ops = {
.get_state = meson_pwm_get_state,
};
static const struct meson_pwm_data pwm_meson8b_data = {
.parent_names = { "xtal", NULL, "fclk_div4", "fclk_div3" },
};
/*
* Only the 2 first inputs of the GXBB AO PWMs are valid
* The last 2 are grounded
*/
static const struct meson_pwm_data pwm_gxbb_ao_data = {
.parent_names = { "xtal", "clk81", NULL, NULL },
};
static const struct meson_pwm_data pwm_axg_ee_data = {
.parent_names = { "xtal", "fclk_div5", "fclk_div4", "fclk_div3" },
};
static const struct meson_pwm_data pwm_axg_ao_data = {
.parent_names = { "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" },
};
static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
.parent_names = { "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" },
};
static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
.parent_names = { "xtal", "g12a_ao_clk81", NULL, NULL },
};
static const struct of_device_id meson_pwm_matches[] = {
{
.compatible = "amlogic,meson8b-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-gxbb-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-gxbb-ao-pwm",
.data = &pwm_gxbb_ao_data
},
{
.compatible = "amlogic,meson-axg-ee-pwm",
.data = &pwm_axg_ee_data
},
{
.compatible = "amlogic,meson-axg-ao-pwm",
.data = &pwm_axg_ao_data
},
{
.compatible = "amlogic,meson-g12a-ee-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-ab",
.data = &pwm_g12a_ao_ab_data
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-cd",
.data = &pwm_g12a_ao_cd_data
},
{},
};
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
static int meson_pwm_init_channels(struct pwm_chip *chip)
static int meson_pwm_init_clocks_meson8b(struct pwm_chip *chip,
struct clk_parent_data *mux_parent_data)
{
struct meson_pwm *meson = to_meson_pwm(chip);
struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {};
struct device *dev = pwmchip_parent(chip);
unsigned int i;
char name[255];
int err;
for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) {
mux_parent_data[i].index = -1;
mux_parent_data[i].name = meson->data->parent_names[i];
}
for (i = 0; i < chip->npwm; i++) {
for (i = 0; i < MESON_NUM_PWMS; i++) {
struct meson_pwm_channel *channel = &meson->channels[i];
struct clk_parent_data div_parent = {}, gate_parent = {};
struct clk_init_data init = {};
......@@ -495,6 +424,122 @@ static int meson_pwm_init_channels(struct pwm_chip *chip)
return 0;
}
static int meson_pwm_init_channels_meson8b_legacy(struct pwm_chip *chip)
{
struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {};
struct meson_pwm *meson = to_meson_pwm(chip);
int i;
dev_warn_once(pwmchip_parent(chip),
"using obsolete compatible, please consider updating dt\n");
for (i = 0; i < MESON_NUM_MUX_PARENTS; i++) {
mux_parent_data[i].index = -1;
mux_parent_data[i].name = meson->data->parent_names[i];
}
return meson_pwm_init_clocks_meson8b(chip, mux_parent_data);
}
static int meson_pwm_init_channels_meson8b_v2(struct pwm_chip *chip)
{
struct clk_parent_data mux_parent_data[MESON_NUM_MUX_PARENTS] = {};
int i;
/*
* NOTE: Instead of relying on the hard coded names in the driver
* as the legacy version, this relies on DT to provide the list of
* clocks.
* For once, using input numbers actually makes more sense than names.
* Also DT requires clock-names to be explicitly ordered, so there is
* no point bothering with clock names in this case.
*/
for (i = 0; i < MESON_NUM_MUX_PARENTS; i++)
mux_parent_data[i].index = i;
return meson_pwm_init_clocks_meson8b(chip, mux_parent_data);
}
static const struct meson_pwm_data pwm_meson8b_data = {
.parent_names = { "xtal", NULL, "fclk_div4", "fclk_div3" },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
/*
* Only the 2 first inputs of the GXBB AO PWMs are valid
* The last 2 are grounded
*/
static const struct meson_pwm_data pwm_gxbb_ao_data = {
.parent_names = { "xtal", "clk81", NULL, NULL },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
static const struct meson_pwm_data pwm_axg_ee_data = {
.parent_names = { "xtal", "fclk_div5", "fclk_div4", "fclk_div3" },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
static const struct meson_pwm_data pwm_axg_ao_data = {
.parent_names = { "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
.parent_names = { "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
.parent_names = { "xtal", "g12a_ao_clk81", NULL, NULL },
.channels_init = meson_pwm_init_channels_meson8b_legacy,
};
static const struct meson_pwm_data pwm_meson8_v2_data = {
.channels_init = meson_pwm_init_channels_meson8b_v2,
};
static const struct of_device_id meson_pwm_matches[] = {
{
.compatible = "amlogic,meson8-pwm-v2",
.data = &pwm_meson8_v2_data
},
/* The following compatibles are obsolete */
{
.compatible = "amlogic,meson8b-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-gxbb-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-gxbb-ao-pwm",
.data = &pwm_gxbb_ao_data
},
{
.compatible = "amlogic,meson-axg-ee-pwm",
.data = &pwm_axg_ee_data
},
{
.compatible = "amlogic,meson-axg-ao-pwm",
.data = &pwm_axg_ao_data
},
{
.compatible = "amlogic,meson-g12a-ee-pwm",
.data = &pwm_meson8b_data
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-ab",
.data = &pwm_g12a_ao_ab_data
},
{
.compatible = "amlogic,meson-g12a-ao-pwm-cd",
.data = &pwm_g12a_ao_cd_data
},
{},
};
MODULE_DEVICE_TABLE(of, meson_pwm_matches);
static int meson_pwm_probe(struct platform_device *pdev)
{
struct pwm_chip *chip;
......@@ -515,7 +560,7 @@ static int meson_pwm_probe(struct platform_device *pdev)
meson->data = of_device_get_match_data(&pdev->dev);
err = meson_pwm_init_channels(chip);
err = meson->data->channels_init(chip);
if (err < 0)
return err;
......
......@@ -634,8 +634,8 @@ static int __maybe_unused pca9685_pwm_runtime_resume(struct device *dev)
}
static const struct i2c_device_id pca9685_id[] = {
{ "pca9685", 0 },
{ /* sentinel */ },
{ "pca9685" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9685_id);
......
......@@ -73,21 +73,16 @@ struct sti_cpt_ddata {
wait_queue_head_t wait;
};
struct sti_pwm_compat_data {
const struct reg_field *reg_fields;
unsigned int pwm_num_devs;
unsigned int cpt_num_devs;
unsigned int max_pwm_cnt;
unsigned int max_prescale;
struct sti_cpt_ddata *ddata;
};
struct sti_pwm_chip {
struct device *dev;
struct clk *pwm_clk;
struct clk *cpt_clk;
struct regmap *regmap;
struct sti_pwm_compat_data *cdata;
unsigned int pwm_num_devs;
unsigned int cpt_num_devs;
unsigned int max_pwm_cnt;
unsigned int max_prescale;
struct sti_cpt_ddata *ddata;
struct regmap_field *prescale_low;
struct regmap_field *prescale_high;
struct regmap_field *pwm_out_en;
......@@ -122,7 +117,6 @@ static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period,
unsigned int *prescale)
{
struct sti_pwm_compat_data *cdata = pc->cdata;
unsigned long clk_rate;
unsigned long value;
unsigned int ps;
......@@ -137,13 +131,13 @@ static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period,
* prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_cnt + 1)) - 1
*/
value = NSEC_PER_SEC / clk_rate;
value *= cdata->max_pwm_cnt + 1;
value *= pc->max_pwm_cnt + 1;
if (period % value)
return -EINVAL;
ps = period / value - 1;
if (ps > cdata->max_prescale)
if (ps > pc->max_prescale)
return -EINVAL;
*prescale = ps;
......@@ -164,7 +158,6 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
struct sti_pwm_compat_data *cdata = pc->cdata;
unsigned int ncfg, value, prescale = 0;
struct pwm_device *cur = pc->cur;
struct device *dev = pc->dev;
......@@ -224,7 +217,7 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* PWM pulse = (max_pwm_count + 1) local cycles,
* that is continuous pulse: signal never goes low.
*/
value = cdata->max_pwm_cnt * duty_ns / period_ns;
value = pc->max_pwm_cnt * duty_ns / period_ns;
ret = regmap_write(pc->regmap, PWM_OUT_VAL(pwm->hwpwm), value);
if (ret)
......@@ -313,14 +306,13 @@ static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_capture *result, unsigned long timeout)
{
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
struct sti_pwm_compat_data *cdata = pc->cdata;
struct sti_cpt_ddata *ddata = &cdata->ddata[pwm->hwpwm];
struct sti_cpt_ddata *ddata = &pc->ddata[pwm->hwpwm];
struct device *dev = pc->dev;
unsigned int effective_ticks;
unsigned long long high, low;
int ret;
if (pwm->hwpwm >= cdata->cpt_num_devs) {
if (pwm->hwpwm >= pc->cpt_num_devs) {
dev_err(dev, "device %u is not valid\n", pwm->hwpwm);
return -EINVAL;
}
......@@ -395,11 +387,10 @@ static int sti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
struct sti_pwm_compat_data *cdata = pc->cdata;
struct device *dev = pc->dev;
int err;
if (pwm->hwpwm >= cdata->pwm_num_devs) {
if (pwm->hwpwm >= pc->pwm_num_devs) {
dev_err(dev, "device %u is not valid for pwm mode\n",
pwm->hwpwm);
return -EINVAL;
......@@ -448,7 +439,7 @@ static irqreturn_t sti_pwm_interrupt(int irq, void *data)
while (cpt_int_stat) {
devicenum = ffs(cpt_int_stat) - 1;
ddata = &pc->cdata->ddata[devicenum];
ddata = &pc->ddata[devicenum];
/*
* Capture input:
......@@ -502,41 +493,37 @@ static irqreturn_t sti_pwm_interrupt(int irq, void *data)
return ret;
}
static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
static int sti_pwm_probe_regmap(struct sti_pwm_chip *pc)
{
struct device *dev = pc->dev;
const struct reg_field *reg_fields;
struct sti_pwm_compat_data *cdata = pc->cdata;
reg_fields = cdata->reg_fields;
pc->prescale_low = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWMCLK_PRESCALE_LOW]);
sti_pwm_regfields[PWMCLK_PRESCALE_LOW]);
if (IS_ERR(pc->prescale_low))
return PTR_ERR(pc->prescale_low);
pc->prescale_high = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWMCLK_PRESCALE_HIGH]);
sti_pwm_regfields[PWMCLK_PRESCALE_HIGH]);
if (IS_ERR(pc->prescale_high))
return PTR_ERR(pc->prescale_high);
pc->pwm_out_en = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWM_OUT_EN]);
sti_pwm_regfields[PWM_OUT_EN]);
if (IS_ERR(pc->pwm_out_en))
return PTR_ERR(pc->pwm_out_en);
pc->pwm_cpt_en = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWM_CPT_EN]);
sti_pwm_regfields[PWM_CPT_EN]);
if (IS_ERR(pc->pwm_cpt_en))
return PTR_ERR(pc->pwm_cpt_en);
pc->pwm_cpt_int_en = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWM_CPT_INT_EN]);
sti_pwm_regfields[PWM_CPT_INT_EN]);
if (IS_ERR(pc->pwm_cpt_int_en))
return PTR_ERR(pc->pwm_cpt_int_en);
pc->pwm_cpt_int_stat = devm_regmap_field_alloc(dev, pc->regmap,
reg_fields[PWM_CPT_INT_STAT]);
sti_pwm_regfields[PWM_CPT_INT_STAT]);
if (PTR_ERR_OR_ZERO(pc->pwm_cpt_int_stat))
return PTR_ERR(pc->pwm_cpt_int_stat);
......@@ -556,7 +543,6 @@ static int sti_pwm_probe(struct platform_device *pdev)
u32 num_devs;
unsigned int pwm_num_devs = 0;
unsigned int cpt_num_devs = 0;
struct sti_pwm_compat_data *cdata;
struct pwm_chip *chip;
struct sti_pwm_chip *pc;
unsigned int i;
......@@ -570,20 +556,14 @@ static int sti_pwm_probe(struct platform_device *pdev)
if (!ret)
cpt_num_devs = num_devs;
if (!pwm_num_devs && !cpt_num_devs) {
dev_err(dev, "No channels configured\n");
return -EINVAL;
}
if (!pwm_num_devs && !cpt_num_devs)
return dev_err_probe(dev, -EINVAL, "No channels configured\n");
chip = devm_pwmchip_alloc(dev, max(pwm_num_devs, cpt_num_devs), sizeof(*pc));
if (IS_ERR(chip))
return PTR_ERR(chip);
pc = to_sti_pwmchip(chip);
cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
pc->mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pc->mmio))
return PTR_ERR(pc->mmio);
......@@ -591,7 +571,8 @@ static int sti_pwm_probe(struct platform_device *pdev)
pc->regmap = devm_regmap_init_mmio(dev, pc->mmio,
&sti_pwm_regmap_config);
if (IS_ERR(pc->regmap))
return PTR_ERR(pc->regmap);
return dev_err_probe(dev, PTR_ERR(pc->regmap),
"Failed to initialize regmap\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
......@@ -599,94 +580,61 @@ static int sti_pwm_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0,
pdev->name, pc);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request IRQ\n");
return ret;
}
if (ret < 0)
dev_err_probe(&pdev->dev, ret, "Failed to request IRQ\n");
/*
* Setup PWM data with default values: some values could be replaced
* with specific ones provided from Device Tree.
*/
cdata->reg_fields = sti_pwm_regfields;
cdata->max_prescale = 0xff;
cdata->max_pwm_cnt = 255;
cdata->pwm_num_devs = pwm_num_devs;
cdata->cpt_num_devs = cpt_num_devs;
pc->max_prescale = 0xff;
pc->max_pwm_cnt = 255;
pc->pwm_num_devs = pwm_num_devs;
pc->cpt_num_devs = cpt_num_devs;
pc->cdata = cdata;
pc->dev = dev;
pc->en_count = 0;
mutex_init(&pc->sti_pwm_lock);
ret = sti_pwm_probe_dt(pc);
ret = sti_pwm_probe_regmap(pc);
if (ret)
return ret;
return dev_err_probe(dev, ret, "Failed to initialize regmap fields\n");
if (cdata->pwm_num_devs) {
pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm");
if (IS_ERR(pc->pwm_clk)) {
dev_err(dev, "failed to get PWM clock\n");
return PTR_ERR(pc->pwm_clk);
}
ret = clk_prepare(pc->pwm_clk);
if (ret) {
dev_err(dev, "failed to prepare clock\n");
return ret;
}
if (pwm_num_devs) {
pc->pwm_clk = devm_clk_get_prepared(dev, "pwm");
if (IS_ERR(pc->pwm_clk))
return dev_err_probe(dev, PTR_ERR(pc->pwm_clk),
"failed to get PWM clock\n");
}
if (cdata->cpt_num_devs) {
pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture");
if (IS_ERR(pc->cpt_clk)) {
dev_err(dev, "failed to get PWM capture clock\n");
return PTR_ERR(pc->cpt_clk);
}
if (cpt_num_devs) {
pc->cpt_clk = devm_clk_get_prepared(dev, "capture");
if (IS_ERR(pc->cpt_clk))
return dev_err_probe(dev, PTR_ERR(pc->cpt_clk),
"failed to get PWM capture clock\n");
ret = clk_prepare(pc->cpt_clk);
if (ret) {
dev_err(dev, "failed to prepare clock\n");
return ret;
}
cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL);
if (!cdata->ddata)
pc->ddata = devm_kcalloc(dev, cpt_num_devs,
sizeof(*pc->ddata), GFP_KERNEL);
if (!pc->ddata)
return -ENOMEM;
}
chip->ops = &sti_pwm_ops;
for (i = 0; i < cpt_num_devs; i++) {
struct sti_cpt_ddata *ddata = &pc->ddata[i];
for (i = 0; i < cdata->cpt_num_devs; i++) {
struct sti_cpt_ddata *ddata = &cdata->ddata[i];
init_waitqueue_head(&ddata->wait);
mutex_init(&ddata->lock);
init_waitqueue_head(&ddata->wait);
mutex_init(&ddata->lock);
}
}
ret = pwmchip_add(chip);
if (ret < 0) {
clk_unprepare(pc->pwm_clk);
clk_unprepare(pc->cpt_clk);
return ret;
}
chip->ops = &sti_pwm_ops;
platform_set_drvdata(pdev, chip);
ret = devm_pwmchip_add(dev, chip);
if (ret)
return dev_err_probe(dev, ret, "Failed to register pwm chip\n");
return 0;
}
static void sti_pwm_remove(struct platform_device *pdev)
{
struct pwm_chip *chip = platform_get_drvdata(pdev);
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
pwmchip_remove(chip);
clk_unprepare(pc->pwm_clk);
clk_unprepare(pc->cpt_clk);
}
static const struct of_device_id sti_pwm_of_match[] = {
{ .compatible = "st,sti-pwm", },
{ /* sentinel */ }
......@@ -699,7 +647,6 @@ static struct platform_driver sti_pwm_driver = {
.of_match_table = sti_pwm_of_match,
},
.probe = sti_pwm_probe,
.remove_new = sti_pwm_remove,
};
module_platform_driver(sti_pwm_driver);
......
......@@ -309,29 +309,35 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
}
static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
int duty_ns, int period_ns)
u64 duty_ns, u64 period_ns)
{
unsigned long long prd, div, dty;
unsigned int prescaler = 0;
unsigned long long prd, dty;
unsigned long long prescaler;
u32 ccmr, mask, shift;
/* Period and prescaler values depends on clock rate */
div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
do_div(div, NSEC_PER_SEC);
prd = div;
while (div > priv->max_arr) {
prescaler++;
div = prd;
do_div(div, prescaler + 1);
}
/*
* .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
* the calculations here won't overflow.
* First we need to find the minimal value for prescaler such that
*
* period_ns * clkrate
* ------------------------------
* NSEC_PER_SEC * (prescaler + 1)
*
* isn't bigger than max_arr.
*/
prd = div;
prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
(u64)NSEC_PER_SEC * priv->max_arr);
if (prescaler > 0)
prescaler -= 1;
if (prescaler > MAX_TIM_PSC)
return -EINVAL;
prd = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
(u64)NSEC_PER_SEC * (prescaler + 1));
/*
* All channels share the same prescaler and counter so when two
* channels are active at the same time we can't change them
......@@ -351,8 +357,8 @@ static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
/* Calculate the duty cycles */
dty = prd * duty_ns;
do_div(dty, period_ns);
dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk),
(u64)NSEC_PER_SEC * (prescaler + 1));
regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty);
......@@ -648,14 +654,27 @@ static int stm32_pwm_probe(struct platform_device *pdev)
priv->max_arr = ddata->max_arr;
if (!priv->regmap || !priv->clk)
return -EINVAL;
return dev_err_probe(dev, -EINVAL, "Failed to get %s\n",
priv->regmap ? "clk" : "regmap");
ret = stm32_pwm_probe_breakinputs(priv, np);
if (ret)
return ret;
return dev_err_probe(dev, ret,
"Failed to configure breakinputs\n");
stm32_pwm_detect_complementary(priv);
ret = devm_clk_rate_exclusive_get(dev, priv->clk);
if (ret)
return dev_err_probe(dev, ret, "Failed to lock clock\n");
/*
* With the clk running with not more than 1 GHz the calculations in
* .apply() won't overflow.
*/
if (clk_get_rate(priv->clk) > 1000000000)
return dev_err_probe(dev, -EINVAL, "Failed to lock clock\n");
chip->ops = &stm32pwm_ops;
/* Initialize clock refcount to number of enabled PWM channels. */
......@@ -664,7 +683,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
ret = devm_pwmchip_add(dev, chip);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret,
"Failed to register pwmchip\n");
platform_set_drvdata(pdev, chip);
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
#ifndef __LINUX_PWM_H
#define __LINUX_PWM_H
#include <linux/device.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of.h>
......@@ -272,11 +273,11 @@ struct pwm_ops {
* @npwm: number of PWMs controlled by this chip
* @of_xlate: request a PWM device given a device tree PWM specifier
* @atomic: can the driver's ->apply() be called in atomic context
* @driver_data: Private pointer for driver specific info
* @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip
* @pwms: array of PWM devices allocated by the framework
*/
struct pwm_chip {
struct device *dev;
struct device dev;
const struct pwm_ops *ops;
struct module *owner;
unsigned int id;
......@@ -287,31 +288,23 @@ struct pwm_chip {
bool atomic;
/* only used internally by the PWM framework */
void *driver_data;
struct pwm_device *pwms;
bool uses_pwmchip_alloc;
struct pwm_device pwms[] __counted_by(npwm);
};
static inline struct device *pwmchip_parent(const struct pwm_chip *chip)
{
return chip->dev;
return chip->dev.parent;
}
static inline void *pwmchip_get_drvdata(struct pwm_chip *chip)
{
/*
* After pwm_chip got a dedicated struct device, this can be replaced by
* dev_get_drvdata(&chip->dev);
*/
return chip->driver_data;
return dev_get_drvdata(&chip->dev);
}
static inline void pwmchip_set_drvdata(struct pwm_chip *chip, void *data)
{
/*
* After pwm_chip got a dedicated struct device, this can be replaced by
* dev_set_drvdata(&chip->dev, data);
*/
chip->driver_data = data;
dev_set_drvdata(&chip->dev, data);
}
#if IS_ENABLED(CONFIG_PWM)
......@@ -628,17 +621,4 @@ static inline void pwm_remove_table(struct pwm_lookup *table, size_t num)
}
#endif
#ifdef CONFIG_PWM_SYSFS
void pwmchip_sysfs_export(struct pwm_chip *chip);
void pwmchip_sysfs_unexport(struct pwm_chip *chip);
#else
static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
{
}
static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
{
}
#endif /* CONFIG_PWM_SYSFS */
#endif /* __LINUX_PWM_H */
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