| .. | .. |
|---|
| 13 | 13 | #include <linux/kernel.h> |
|---|
| 14 | 14 | #include <linux/module.h> |
|---|
| 15 | 15 | #include <linux/platform_device.h> |
|---|
| 16 | +#include <linux/pm_runtime.h> |
|---|
| 16 | 17 | |
|---|
| 17 | 18 | #include "stm32-dac-core.h" |
|---|
| 18 | 19 | |
|---|
| .. | .. |
|---|
| 20 | 21 | #define STM32_DAC_CHANNEL_2 2 |
|---|
| 21 | 22 | #define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1) |
|---|
| 22 | 23 | |
|---|
| 24 | +#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000 |
|---|
| 25 | + |
|---|
| 23 | 26 | /** |
|---|
| 24 | 27 | * struct stm32_dac - private data of DAC driver |
|---|
| 25 | 28 | * @common: reference to DAC common data |
|---|
| 29 | + * @lock: lock to protect against potential races when reading |
|---|
| 30 | + * and update CR, to keep it in sync with pm_runtime |
|---|
| 26 | 31 | */ |
|---|
| 27 | 32 | struct stm32_dac { |
|---|
| 28 | 33 | struct stm32_dac_common *common; |
|---|
| 34 | + struct mutex lock; |
|---|
| 29 | 35 | }; |
|---|
| 30 | 36 | |
|---|
| 31 | 37 | static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel) |
|---|
| .. | .. |
|---|
| 49 | 55 | bool enable) |
|---|
| 50 | 56 | { |
|---|
| 51 | 57 | struct stm32_dac *dac = iio_priv(indio_dev); |
|---|
| 58 | + struct device *dev = indio_dev->dev.parent; |
|---|
| 52 | 59 | u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2; |
|---|
| 53 | 60 | u32 en = enable ? msk : 0; |
|---|
| 54 | 61 | int ret; |
|---|
| 55 | 62 | |
|---|
| 63 | + /* already enabled / disabled ? */ |
|---|
| 64 | + mutex_lock(&dac->lock); |
|---|
| 65 | + ret = stm32_dac_is_enabled(indio_dev, ch); |
|---|
| 66 | + if (ret < 0 || enable == !!ret) { |
|---|
| 67 | + mutex_unlock(&dac->lock); |
|---|
| 68 | + return ret < 0 ? ret : 0; |
|---|
| 69 | + } |
|---|
| 70 | + |
|---|
| 71 | + if (enable) { |
|---|
| 72 | + ret = pm_runtime_get_sync(dev); |
|---|
| 73 | + if (ret < 0) { |
|---|
| 74 | + pm_runtime_put_noidle(dev); |
|---|
| 75 | + mutex_unlock(&dac->lock); |
|---|
| 76 | + return ret; |
|---|
| 77 | + } |
|---|
| 78 | + } |
|---|
| 79 | + |
|---|
| 56 | 80 | ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en); |
|---|
| 81 | + mutex_unlock(&dac->lock); |
|---|
| 57 | 82 | if (ret < 0) { |
|---|
| 58 | 83 | dev_err(&indio_dev->dev, "%s failed\n", en ? |
|---|
| 59 | 84 | "Enable" : "Disable"); |
|---|
| 60 | | - return ret; |
|---|
| 85 | + goto err_put_pm; |
|---|
| 61 | 86 | } |
|---|
| 62 | 87 | |
|---|
| 63 | 88 | /* |
|---|
| .. | .. |
|---|
| 68 | 93 | if (en && dac->common->hfsel) |
|---|
| 69 | 94 | udelay(1); |
|---|
| 70 | 95 | |
|---|
| 96 | + if (!enable) { |
|---|
| 97 | + pm_runtime_mark_last_busy(dev); |
|---|
| 98 | + pm_runtime_put_autosuspend(dev); |
|---|
| 99 | + } |
|---|
| 100 | + |
|---|
| 71 | 101 | return 0; |
|---|
| 102 | + |
|---|
| 103 | +err_put_pm: |
|---|
| 104 | + if (enable) { |
|---|
| 105 | + pm_runtime_mark_last_busy(dev); |
|---|
| 106 | + pm_runtime_put_autosuspend(dev); |
|---|
| 107 | + } |
|---|
| 108 | + |
|---|
| 109 | + return ret; |
|---|
| 72 | 110 | } |
|---|
| 73 | 111 | |
|---|
| 74 | 112 | static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val) |
|---|
| .. | .. |
|---|
| 272 | 310 | static int stm32_dac_probe(struct platform_device *pdev) |
|---|
| 273 | 311 | { |
|---|
| 274 | 312 | struct device_node *np = pdev->dev.of_node; |
|---|
| 313 | + struct device *dev = &pdev->dev; |
|---|
| 275 | 314 | struct iio_dev *indio_dev; |
|---|
| 276 | 315 | struct stm32_dac *dac; |
|---|
| 277 | 316 | int ret; |
|---|
| .. | .. |
|---|
| 287 | 326 | dac = iio_priv(indio_dev); |
|---|
| 288 | 327 | dac->common = dev_get_drvdata(pdev->dev.parent); |
|---|
| 289 | 328 | indio_dev->name = dev_name(&pdev->dev); |
|---|
| 290 | | - indio_dev->dev.parent = &pdev->dev; |
|---|
| 291 | 329 | indio_dev->dev.of_node = pdev->dev.of_node; |
|---|
| 292 | 330 | indio_dev->info = &stm32_dac_iio_info; |
|---|
| 293 | 331 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 332 | + |
|---|
| 333 | + mutex_init(&dac->lock); |
|---|
| 294 | 334 | |
|---|
| 295 | 335 | ret = stm32_dac_chan_of_init(indio_dev); |
|---|
| 296 | 336 | if (ret < 0) |
|---|
| 297 | 337 | return ret; |
|---|
| 298 | 338 | |
|---|
| 299 | | - return devm_iio_device_register(&pdev->dev, indio_dev); |
|---|
| 339 | + /* Get stm32-dac-core PM online */ |
|---|
| 340 | + pm_runtime_get_noresume(dev); |
|---|
| 341 | + pm_runtime_set_active(dev); |
|---|
| 342 | + pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS); |
|---|
| 343 | + pm_runtime_use_autosuspend(dev); |
|---|
| 344 | + pm_runtime_enable(dev); |
|---|
| 345 | + |
|---|
| 346 | + ret = iio_device_register(indio_dev); |
|---|
| 347 | + if (ret) |
|---|
| 348 | + goto err_pm_put; |
|---|
| 349 | + |
|---|
| 350 | + pm_runtime_mark_last_busy(dev); |
|---|
| 351 | + pm_runtime_put_autosuspend(dev); |
|---|
| 352 | + |
|---|
| 353 | + return 0; |
|---|
| 354 | + |
|---|
| 355 | +err_pm_put: |
|---|
| 356 | + pm_runtime_disable(dev); |
|---|
| 357 | + pm_runtime_set_suspended(dev); |
|---|
| 358 | + pm_runtime_put_noidle(dev); |
|---|
| 359 | + |
|---|
| 360 | + return ret; |
|---|
| 300 | 361 | } |
|---|
| 362 | + |
|---|
| 363 | +static int stm32_dac_remove(struct platform_device *pdev) |
|---|
| 364 | +{ |
|---|
| 365 | + struct iio_dev *indio_dev = platform_get_drvdata(pdev); |
|---|
| 366 | + |
|---|
| 367 | + pm_runtime_get_sync(&pdev->dev); |
|---|
| 368 | + iio_device_unregister(indio_dev); |
|---|
| 369 | + pm_runtime_disable(&pdev->dev); |
|---|
| 370 | + pm_runtime_set_suspended(&pdev->dev); |
|---|
| 371 | + pm_runtime_put_noidle(&pdev->dev); |
|---|
| 372 | + |
|---|
| 373 | + return 0; |
|---|
| 374 | +} |
|---|
| 375 | + |
|---|
| 376 | +static int __maybe_unused stm32_dac_suspend(struct device *dev) |
|---|
| 377 | +{ |
|---|
| 378 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); |
|---|
| 379 | + int channel = indio_dev->channels[0].channel; |
|---|
| 380 | + int ret; |
|---|
| 381 | + |
|---|
| 382 | + /* Ensure DAC is disabled before suspend */ |
|---|
| 383 | + ret = stm32_dac_is_enabled(indio_dev, channel); |
|---|
| 384 | + if (ret) |
|---|
| 385 | + return ret < 0 ? ret : -EBUSY; |
|---|
| 386 | + |
|---|
| 387 | + return pm_runtime_force_suspend(dev); |
|---|
| 388 | +} |
|---|
| 389 | + |
|---|
| 390 | +static const struct dev_pm_ops stm32_dac_pm_ops = { |
|---|
| 391 | + SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume) |
|---|
| 392 | +}; |
|---|
| 301 | 393 | |
|---|
| 302 | 394 | static const struct of_device_id stm32_dac_of_match[] = { |
|---|
| 303 | 395 | { .compatible = "st,stm32-dac", }, |
|---|
| .. | .. |
|---|
| 307 | 399 | |
|---|
| 308 | 400 | static struct platform_driver stm32_dac_driver = { |
|---|
| 309 | 401 | .probe = stm32_dac_probe, |
|---|
| 402 | + .remove = stm32_dac_remove, |
|---|
| 310 | 403 | .driver = { |
|---|
| 311 | 404 | .name = "stm32-dac", |
|---|
| 312 | 405 | .of_match_table = stm32_dac_of_match, |
|---|
| 406 | + .pm = &stm32_dac_pm_ops, |
|---|
| 313 | 407 | }, |
|---|
| 314 | 408 | }; |
|---|
| 315 | 409 | module_platform_driver(stm32_dac_driver); |
|---|