pwm-ntxec.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * The Netronix embedded controller is a microcontroller found in some
  4. * e-book readers designed by the original design manufacturer Netronix, Inc.
  5. * It contains RTC, battery monitoring, system power management, and PWM
  6. * functionality.
  7. *
  8. * This driver implements PWM output.
  9. *
  10. * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
  11. *
  12. * Limitations:
  13. * - The get_state callback is not implemented, because the current state of
  14. * the PWM output can't be read back from the hardware.
  15. * - The hardware can only generate normal polarity output.
  16. * - The period and duty cycle can't be changed together in one atomic action.
  17. */
  18. #include <linux/mfd/ntxec.h>
  19. #include <linux/module.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/pwm.h>
  22. #include <linux/regmap.h>
  23. #include <linux/types.h>
  24. struct ntxec_pwm {
  25. struct ntxec *ec;
  26. };
  27. static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
  28. {
  29. return pwmchip_get_drvdata(chip);
  30. }
  31. #define NTXEC_REG_AUTO_OFF_HI 0xa1
  32. #define NTXEC_REG_AUTO_OFF_LO 0xa2
  33. #define NTXEC_REG_ENABLE 0xa3
  34. #define NTXEC_REG_PERIOD_LOW 0xa4
  35. #define NTXEC_REG_PERIOD_HIGH 0xa5
  36. #define NTXEC_REG_DUTY_LOW 0xa6
  37. #define NTXEC_REG_DUTY_HIGH 0xa7
  38. /*
  39. * The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are
  40. * measured in this unit.
  41. */
  42. #define TIME_BASE_NS 125
  43. /*
  44. * The maximum input value (in nanoseconds) is determined by the time base and
  45. * the range of the hardware registers that hold the converted value.
  46. * It fits into 32 bits, so we can do our calculations in 32 bits as well.
  47. */
  48. #define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff)
  49. static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip,
  50. int period, int duty)
  51. {
  52. struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
  53. /*
  54. * Changes to the period and duty cycle take effect as soon as the
  55. * corresponding low byte is written, so the hardware may be configured
  56. * to an inconsistent state after the period is written and before the
  57. * duty cycle is fully written. If, in such a case, the old duty cycle
  58. * is longer than the new period, the EC may output 100% for a moment.
  59. *
  60. * To minimize the time between the changes to period and duty cycle
  61. * taking effect, the writes are interleaved.
  62. */
  63. struct reg_sequence regs[] = {
  64. { NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8) },
  65. { NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8) },
  66. { NTXEC_REG_PERIOD_LOW, ntxec_reg8(period) },
  67. { NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) },
  68. };
  69. return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs));
  70. }
  71. static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
  72. const struct pwm_state *state)
  73. {
  74. struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
  75. unsigned int period, duty;
  76. int res;
  77. if (state->polarity != PWM_POLARITY_NORMAL)
  78. return -EINVAL;
  79. period = min_t(u64, state->period, MAX_PERIOD_NS);
  80. duty = min_t(u64, state->duty_cycle, period);
  81. period /= TIME_BASE_NS;
  82. duty /= TIME_BASE_NS;
  83. /*
  84. * Writing a duty cycle of zero puts the device into a state where
  85. * writing a higher duty cycle doesn't result in the brightness that it
  86. * usually results in. This can be fixed by cycling the ENABLE register.
  87. *
  88. * As a workaround, write ENABLE=0 when the duty cycle is zero.
  89. * The case that something has previously set the duty cycle to zero
  90. * but ENABLE=1, is not handled.
  91. */
  92. if (state->enabled && duty != 0) {
  93. res = ntxec_pwm_set_raw_period_and_duty_cycle(chip, period, duty);
  94. if (res)
  95. return res;
  96. res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1));
  97. if (res)
  98. return res;
  99. /* Disable the auto-off timer */
  100. res = regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff));
  101. if (res)
  102. return res;
  103. return regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff));
  104. } else {
  105. return regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0));
  106. }
  107. }
  108. static const struct pwm_ops ntxec_pwm_ops = {
  109. .apply = ntxec_pwm_apply,
  110. /*
  111. * No .get_state callback, because the current state cannot be read
  112. * back from the hardware.
  113. */
  114. };
  115. static int ntxec_pwm_probe(struct platform_device *pdev)
  116. {
  117. struct ntxec *ec = dev_get_drvdata(pdev->dev.parent);
  118. struct ntxec_pwm *priv;
  119. struct pwm_chip *chip;
  120. device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
  121. chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
  122. if (IS_ERR(chip))
  123. return PTR_ERR(chip);
  124. priv = ntxec_pwm_from_chip(chip);
  125. priv->ec = ec;
  126. chip->ops = &ntxec_pwm_ops;
  127. return devm_pwmchip_add(&pdev->dev, chip);
  128. }
  129. static struct platform_driver ntxec_pwm_driver = {
  130. .driver = {
  131. .name = "ntxec-pwm",
  132. },
  133. .probe = ntxec_pwm_probe,
  134. };
  135. module_platform_driver(ntxec_pwm_driver);
  136. MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
  137. MODULE_DESCRIPTION("PWM driver for Netronix EC");
  138. MODULE_LICENSE("GPL");
  139. MODULE_ALIAS("platform:ntxec-pwm");