pwm-adp5585.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Analog Devices ADP5585 PWM driver
  4. *
  5. * Copyright 2022 NXP
  6. * Copyright 2024 Ideas on Board Oy
  7. *
  8. * Limitations:
  9. * - The .apply() operation executes atomically, but may not wait for the
  10. * period to complete (this is not documented and would need to be tested).
  11. * - Disabling the PWM drives the output pin to a low level immediately.
  12. * - The hardware can only generate normal polarity output.
  13. */
  14. #include <asm/byteorder.h>
  15. #include <linux/device.h>
  16. #include <linux/err.h>
  17. #include <linux/math64.h>
  18. #include <linux/mfd/adp5585.h>
  19. #include <linux/minmax.h>
  20. #include <linux/module.h>
  21. #include <linux/mod_devicetable.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/pwm.h>
  24. #include <linux/regmap.h>
  25. #include <linux/time.h>
  26. #include <linux/types.h>
  27. #define ADP5585_PWM_CHAN_NUM 1
  28. #define ADP5585_PWM_OSC_FREQ_HZ 1000000U
  29. #define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
  30. #define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
  31. struct adp5585_pwm_chip {
  32. unsigned int pwm_cfg;
  33. unsigned int pwm_offt_low;
  34. unsigned int pwm_ont_low;
  35. };
  36. struct adp5585_pwm {
  37. const struct adp5585_pwm_chip *info;
  38. struct regmap *regmap;
  39. unsigned int ext_cfg;
  40. };
  41. static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm)
  42. {
  43. struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
  44. /* Configure the R3 pin as PWM output. */
  45. return regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
  46. ADP5585_R3_EXTEND_CFG_MASK,
  47. ADP5585_R3_EXTEND_CFG_PWM_OUT);
  48. }
  49. static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm)
  50. {
  51. struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
  52. regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
  53. ADP5585_R3_EXTEND_CFG_MASK,
  54. ADP5585_R3_EXTEND_CFG_GPIO4);
  55. }
  56. static int pwm_adp5585_apply(struct pwm_chip *chip,
  57. struct pwm_device *pwm,
  58. const struct pwm_state *state)
  59. {
  60. struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
  61. const struct adp5585_pwm_chip *info = adp5585_pwm->info;
  62. struct regmap *regmap = adp5585_pwm->regmap;
  63. u64 period, duty_cycle;
  64. u32 on, off;
  65. __le16 val;
  66. int ret;
  67. if (!state->enabled) {
  68. regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
  69. return 0;
  70. }
  71. if (state->polarity != PWM_POLARITY_NORMAL)
  72. return -EINVAL;
  73. if (state->period < ADP5585_PWM_MIN_PERIOD_NS)
  74. return -EINVAL;
  75. period = min(state->period, ADP5585_PWM_MAX_PERIOD_NS);
  76. duty_cycle = min(state->duty_cycle, period);
  77. /*
  78. * Compute the on and off time. As the internal oscillator frequency is
  79. * 1MHz, the calculation can be simplified without loss of precision.
  80. */
  81. on = div_u64(duty_cycle, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ);
  82. off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on;
  83. val = cpu_to_le16(off);
  84. ret = regmap_bulk_write(regmap, info->pwm_offt_low, &val, 2);
  85. if (ret)
  86. return ret;
  87. val = cpu_to_le16(on);
  88. ret = regmap_bulk_write(regmap, info->pwm_ont_low, &val, 2);
  89. if (ret)
  90. return ret;
  91. /* Enable PWM in continuous mode and no external AND'ing. */
  92. ret = regmap_update_bits(regmap, info->pwm_cfg,
  93. ADP5585_PWM_IN_AND | ADP5585_PWM_MODE |
  94. ADP5585_PWM_EN, ADP5585_PWM_EN);
  95. if (ret)
  96. return ret;
  97. return regmap_set_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
  98. }
  99. static int pwm_adp5585_get_state(struct pwm_chip *chip,
  100. struct pwm_device *pwm,
  101. struct pwm_state *state)
  102. {
  103. struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
  104. const struct adp5585_pwm_chip *info = adp5585_pwm->info;
  105. struct regmap *regmap = adp5585_pwm->regmap;
  106. unsigned int on, off;
  107. unsigned int val;
  108. __le16 on_off;
  109. int ret;
  110. ret = regmap_bulk_read(regmap, info->pwm_offt_low, &on_off, 2);
  111. if (ret)
  112. return ret;
  113. off = le16_to_cpu(on_off);
  114. ret = regmap_bulk_read(regmap, info->pwm_ont_low, &on_off, 2);
  115. if (ret)
  116. return ret;
  117. on = le16_to_cpu(on_off);
  118. state->duty_cycle = on * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ);
  119. state->period = (on + off) * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ);
  120. state->polarity = PWM_POLARITY_NORMAL;
  121. regmap_read(regmap, info->pwm_cfg, &val);
  122. state->enabled = !!(val & ADP5585_PWM_EN);
  123. return 0;
  124. }
  125. static const struct pwm_ops adp5585_pwm_ops = {
  126. .request = pwm_adp5585_request,
  127. .free = pwm_adp5585_free,
  128. .apply = pwm_adp5585_apply,
  129. .get_state = pwm_adp5585_get_state,
  130. };
  131. static int adp5585_pwm_probe(struct platform_device *pdev)
  132. {
  133. const struct platform_device_id *id = platform_get_device_id(pdev);
  134. struct device *dev = &pdev->dev;
  135. struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
  136. struct adp5585_pwm *adp5585_pwm;
  137. struct pwm_chip *chip;
  138. int ret;
  139. chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM,
  140. sizeof(*adp5585_pwm));
  141. if (IS_ERR(chip))
  142. return PTR_ERR(chip);
  143. adp5585_pwm = pwmchip_get_drvdata(chip);
  144. adp5585_pwm->regmap = adp5585->regmap;
  145. adp5585_pwm->ext_cfg = adp5585->regs->ext_cfg;
  146. adp5585_pwm->info = (const struct adp5585_pwm_chip *)id->driver_data;
  147. if (!adp5585_pwm->info)
  148. return -ENODEV;
  149. device_set_of_node_from_dev(dev, dev->parent);
  150. chip->ops = &adp5585_pwm_ops;
  151. ret = devm_pwmchip_add(dev, chip);
  152. if (ret)
  153. return dev_err_probe(dev, ret, "failed to add PWM chip\n");
  154. return 0;
  155. }
  156. static const struct adp5585_pwm_chip adp5585_pwm_chip_info = {
  157. .pwm_cfg = ADP5585_PWM_CFG,
  158. .pwm_offt_low = ADP5585_PWM_OFFT_LOW,
  159. .pwm_ont_low = ADP5585_PWM_ONT_LOW,
  160. };
  161. static const struct adp5585_pwm_chip adp5589_pwm_chip_info = {
  162. .pwm_cfg = ADP5589_PWM_CFG,
  163. .pwm_offt_low = ADP5589_PWM_OFFT_LOW,
  164. .pwm_ont_low = ADP5589_PWM_ONT_LOW,
  165. };
  166. static const struct platform_device_id adp5585_pwm_id_table[] = {
  167. { "adp5585-pwm", (kernel_ulong_t)&adp5585_pwm_chip_info },
  168. { "adp5589-pwm", (kernel_ulong_t)&adp5589_pwm_chip_info },
  169. { /* Sentinel */ }
  170. };
  171. MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table);
  172. static struct platform_driver adp5585_pwm_driver = {
  173. .driver = {
  174. .name = "adp5585-pwm",
  175. },
  176. .probe = adp5585_pwm_probe,
  177. .id_table = adp5585_pwm_id_table,
  178. };
  179. module_platform_driver(adp5585_pwm_driver);
  180. MODULE_AUTHOR("Xiaoning Wang <xiaoning.wang@nxp.com>");
  181. MODULE_DESCRIPTION("ADP5585 PWM Driver");
  182. MODULE_LICENSE("GPL");