0018-iot2000-hack-pwm-pca-9685-Provide-chip-level-pwm_per.patch 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. From c25a8e605bcbb0ed2adde384587ffcfcf5783eef Mon Sep 17 00:00:00 2001
  2. From: Jan Kiszka <jan.kiszka@siemens.com>
  3. Date: Fri, 17 Nov 2017 20:25:54 +0100
  4. Subject: [PATCH 18/18] iot2000-hack: pwm: pca-9685: Provide chip-level
  5. pwm_period attribute
  6. Arduino runtime relies on this path to program the PWM period, rather
  7. than doing this via the upstream kernel API which is per channel.
  8. Another one not for upstream.
  9. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
  10. ---
  11. drivers/pwm/pwm-pca9685.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
  12. 1 file changed, 59 insertions(+)
  13. diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
  14. index 611b9263a896..ce765f903714 100644
  15. --- a/drivers/pwm/pwm-pca9685.c
  16. +++ b/drivers/pwm/pwm-pca9685.c
  17. @@ -444,6 +444,54 @@ static const struct pwm_ops pca9685_pwm_ops = {
  18. .owner = THIS_MODULE,
  19. };
  20. +static ssize_t pwm_period_show(struct device *parent,
  21. + struct device_attribute *attr,
  22. + char *buf)
  23. +{
  24. + struct pwm_chip *chip = dev_get_drvdata(parent);
  25. +
  26. + return sprintf(buf, "%u\n", to_pca(chip)->period_ns);
  27. +}
  28. +
  29. +static ssize_t pwm_period_store(struct device *parent,
  30. + struct device_attribute *attr,
  31. + const char *buf, size_t size)
  32. +{
  33. + struct pwm_chip *chip = dev_get_drvdata(parent);
  34. + struct pca9685 *pca = to_pca(chip);
  35. + int old_period_ns = pca->period_ns;
  36. + unsigned long long duty_scale, new_duty_ns;
  37. + unsigned int val, channel;
  38. + struct pwm_device *pwm;
  39. + int ret;
  40. +
  41. + ret = kstrtouint(buf, 0, &val);
  42. + if (ret)
  43. + return ret;
  44. +
  45. + for (channel = 0; channel < PCA9685_MAXCHAN; channel++) {
  46. + pwm = &chip->pwms[channel];
  47. +
  48. + if (pca9685_pwm_is_gpio(pca, pwm))
  49. + continue;
  50. +
  51. + /* Scale the rise time to maintain duty cycle */
  52. + duty_scale = val;
  53. + duty_scale *= 1000000;
  54. + do_div(duty_scale, old_period_ns);
  55. + new_duty_ns = duty_scale * pwm_get_duty_cycle(pwm);
  56. + do_div(new_duty_ns, 1000000);
  57. + /* Update the duty_cycle */
  58. + ret = pwm_config(pwm, (int)new_duty_ns, val);
  59. + if (ret)
  60. + return ret;
  61. + }
  62. +
  63. + return size;
  64. +}
  65. +
  66. +static DEVICE_ATTR_RW(pwm_period);
  67. +
  68. static const struct regmap_config pca9685_regmap_i2c_config = {
  69. .reg_bits = 8,
  70. .val_bits = 8,
  71. @@ -504,8 +552,17 @@ static int pca9685_pwm_probe(struct i2c_client *client,
  72. if (ret < 0)
  73. return ret;
  74. + ret = sysfs_create_file(&pca->chip.dev->kobj,
  75. + &dev_attr_pwm_period.attr);
  76. + if (ret < 0) {
  77. + pwmchip_remove(&pca->chip);
  78. + return ret;
  79. + }
  80. +
  81. ret = pca9685_pwm_gpio_probe(pca);
  82. if (ret < 0) {
  83. + sysfs_remove_file(&pca->chip.dev->kobj,
  84. + &dev_attr_pwm_period.attr);
  85. pwmchip_remove(&pca->chip);
  86. return ret;
  87. }
  88. @@ -526,6 +583,8 @@ static int pca9685_pwm_remove(struct i2c_client *client)
  89. struct pca9685 *pca = i2c_get_clientdata(client);
  90. int ret;
  91. + sysfs_remove_file(&pca->chip.dev->kobj, &dev_attr_pwm_period.attr);
  92. +
  93. ret = pwmchip_remove(&pca->chip);
  94. if (ret)
  95. return ret;
  96. --
  97. 2.16.4