summaryrefslogtreecommitdiff
path: root/drivers/pwm/pwm-sti.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-05-14 15:03:19 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-05-14 15:03:19 -0700
commit9d81e2d5a9e4befa119e40742a60c366e15d76ce (patch)
treef16cc19e854074d8a9844129e24396031b317906 /drivers/pwm/pwm-sti.c
parent00fddaf58854717a075f3690c828b61290701e7e (diff)
parent4817118f257e49b043f3d80f021a327b7e1d796f (diff)
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 ...
Diffstat (limited to 'drivers/pwm/pwm-sti.c')
-rw-r--r--drivers/pwm/pwm-sti.c159
1 files changed, 53 insertions, 106 deletions
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index 39d80da0e14a..396b52672ce0 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -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);