2
0

0063-pwm-starfive-Add-PWM-driver-support.patch 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. From fddea961e7ce1f26dd549e3d92ede624246690c0 Mon Sep 17 00:00:00 2001
  2. From: William Qiu <[email protected]>
  3. Date: Tue, 21 Mar 2023 13:52:28 +0800
  4. Subject: [PATCH 063/122] pwm: starfive: Add PWM driver support
  5. Add Pulse Width Modulation driver support for StarFive
  6. JH7110 soc.
  7. Signed-off-by: Hal Feng <[email protected]>
  8. Signed-off-by: William Qiu <[email protected]>
  9. ---
  10. drivers/pwm/Kconfig | 10 ++
  11. drivers/pwm/Makefile | 1 +
  12. drivers/pwm/pwm-starfive-ptc.c | 245 +++++++++++++++++++++++++++++++++
  13. 3 files changed, 256 insertions(+)
  14. create mode 100644 drivers/pwm/pwm-starfive-ptc.c
  15. --- a/drivers/pwm/Kconfig
  16. +++ b/drivers/pwm/Kconfig
  17. @@ -536,6 +536,16 @@ config PWM_SPRD
  18. To compile this driver as a module, choose M here: the module
  19. will be called pwm-sprd.
  20. +config PWM_STARFIVE_PTC
  21. + tristate "StarFive PWM PTC support"
  22. + depends on OF
  23. + depends on COMMON_CLK
  24. + help
  25. + Generic PWM framework driver for StarFive SoCs.
  26. +
  27. + To compile this driver as a module, choose M here: the module
  28. + will be called pwm-starfive-ptc.
  29. +
  30. config PWM_STI
  31. tristate "STiH4xx PWM support"
  32. depends on ARCH_STI || COMPILE_TEST
  33. --- a/drivers/pwm/Makefile
  34. +++ b/drivers/pwm/Makefile
  35. @@ -49,6 +49,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
  36. obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
  37. obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
  38. obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o
  39. +obj-$(CONFIG_PWM_STARFIVE_PTC) += pwm-starfive-ptc.o
  40. obj-$(CONFIG_PWM_STI) += pwm-sti.o
  41. obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
  42. obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
  43. --- /dev/null
  44. +++ b/drivers/pwm/pwm-starfive-ptc.c
  45. @@ -0,0 +1,245 @@
  46. +// SPDX-License-Identifier: GPL-2.0
  47. +/*
  48. + * PWM driver for the StarFive JH7110 SoC
  49. + *
  50. + * Copyright (C) 2018 StarFive Technology Co., Ltd.
  51. + */
  52. +
  53. +#include <dt-bindings/pwm/pwm.h>
  54. +#include <linux/module.h>
  55. +#include <linux/platform_device.h>
  56. +#include <linux/pwm.h>
  57. +#include <linux/slab.h>
  58. +#include <linux/clk.h>
  59. +#include <linux/reset.h>
  60. +#include <linux/io.h>
  61. +
  62. +/* how many parameters can be transferred to ptc */
  63. +#define OF_PWM_N_CELLS 3
  64. +
  65. +/* PTC Register offsets */
  66. +#define REG_RPTC_CNTR 0x0
  67. +#define REG_RPTC_HRC 0x4
  68. +#define REG_RPTC_LRC 0x8
  69. +#define REG_RPTC_CTRL 0xC
  70. +
  71. +/* Bit for PWM clock */
  72. +#define BIT_PWM_CLOCK_EN 31
  73. +
  74. +/* Bit for clock gen soft reset */
  75. +#define BIT_CLK_GEN_SOFT_RESET 13
  76. +
  77. +#define NS_PER_SECOND 1000000000
  78. +
  79. +/*
  80. + * Access PTC register (cntr hrc lrc and ctrl),
  81. + * need to replace PWM_BASE_ADDR
  82. + */
  83. +#define REG_PTC_BASE_ADDR_SUB(base, N) \
  84. +((base) + (((N) > 3) ? (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10)))
  85. +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N))
  86. +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4)
  87. +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8)
  88. +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC)
  89. +
  90. +/* PTC_RPTC_CTRL */
  91. +#define PTC_EN BIT(0)
  92. +#define PTC_ECLK BIT(1)
  93. +#define PTC_NEC BIT(2)
  94. +#define PTC_OE BIT(3)
  95. +#define PTC_SIGNLE BIT(4)
  96. +#define PTC_INTE BIT(5)
  97. +#define PTC_INT BIT(6)
  98. +#define PTC_CNTRRST BIT(7)
  99. +#define PTC_CAPTE BIT(8)
  100. +
  101. +struct starfive_pwm_ptc_device {
  102. + struct pwm_chip chip;
  103. + struct clk *clk;
  104. + struct reset_control *rst;
  105. + void __iomem *regs;
  106. + int irq;
  107. + unsigned int approx_freq;/*pwm apb clock frequency*/
  108. +};
  109. +
  110. +static inline
  111. +struct starfive_pwm_ptc_device *chip_to_starfive_ptc(struct pwm_chip *c)
  112. +{
  113. + return container_of(c, struct starfive_pwm_ptc_device, chip);
  114. +}
  115. +
  116. +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip,
  117. + struct pwm_device *dev,
  118. + struct pwm_state *state)
  119. +{
  120. + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip);
  121. + u32 data_lrc, data_hrc;
  122. + u32 pwm_clk_ns = 0;
  123. +
  124. + data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm));
  125. + data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm));
  126. +
  127. + pwm_clk_ns = NS_PER_SECOND / pwm->approx_freq;
  128. +
  129. + state->period = data_lrc * pwm_clk_ns;
  130. + state->duty_cycle = data_hrc * pwm_clk_ns;
  131. + state->polarity = PWM_POLARITY_NORMAL;
  132. + state->enabled = 1;
  133. +
  134. + return 0;
  135. +}
  136. +
  137. +static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
  138. + struct pwm_device *dev,
  139. + struct pwm_state *state)
  140. +{
  141. + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip);
  142. + u32 data_hrc = 0;
  143. + u32 data_lrc = 0;
  144. + u32 period_data = 0;
  145. + u32 duty_data = 0;
  146. + s64 multi = pwm->approx_freq;
  147. + s64 div = NS_PER_SECOND;
  148. + void __iomem *reg_addr;
  149. +
  150. + if (state->duty_cycle > state->period)
  151. + state->duty_cycle = state->period;
  152. +
  153. + while (multi % 10 == 0 && div % 10 == 0 && multi > 0 && div > 0) {
  154. + multi /= 10;
  155. + div /= 10;
  156. + }
  157. +
  158. + period_data = (u32)(state->period * multi / div);
  159. + if (abs(period_data * div / multi - state->period)
  160. + > abs((period_data + 1) * div / multi - state->period) ||
  161. + (state->period > 0 && period_data == 0))
  162. + period_data += 1;
  163. +
  164. + if (state->enabled) {
  165. + duty_data = (u32)(state->duty_cycle * multi / div);
  166. + if (abs(duty_data * div / multi - state->duty_cycle)
  167. + > abs((duty_data + 1) * div / multi - state->duty_cycle) ||
  168. + (state->duty_cycle > 0 && duty_data == 0))
  169. + duty_data += 1;
  170. + } else {
  171. + duty_data = 0;
  172. + }
  173. +
  174. + if (state->polarity == PWM_POLARITY_NORMAL)
  175. + data_hrc = period_data - duty_data;
  176. + else
  177. + data_hrc = duty_data;
  178. +
  179. + data_lrc = period_data;
  180. +
  181. + reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm);
  182. + iowrite32(data_hrc, reg_addr);
  183. +
  184. + reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm);
  185. + iowrite32(data_lrc, reg_addr);
  186. +
  187. + reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm);
  188. + iowrite32(0, reg_addr);
  189. +
  190. + reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm);
  191. + iowrite32(PTC_EN | PTC_OE, reg_addr);
  192. +
  193. + return 0;
  194. +}
  195. +
  196. +static const struct pwm_ops starfive_pwm_ptc_ops = {
  197. + .get_state = starfive_pwm_ptc_get_state,
  198. + .apply = (void *)starfive_pwm_ptc_apply,
  199. + .owner = THIS_MODULE,
  200. +};
  201. +
  202. +static int starfive_pwm_ptc_probe(struct platform_device *pdev)
  203. +{
  204. + struct device *dev = &pdev->dev;
  205. + struct starfive_pwm_ptc_device *pwm;
  206. + struct pwm_chip *chip;
  207. + int ret;
  208. +
  209. + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
  210. + if (!pwm)
  211. + return -ENOMEM;
  212. +
  213. + chip = &pwm->chip;
  214. + chip->dev = dev;
  215. + chip->ops = &starfive_pwm_ptc_ops;
  216. + chip->npwm = 8;
  217. +
  218. + chip->of_pwm_n_cells = OF_PWM_N_CELLS;
  219. + chip->base = -1;
  220. +
  221. + pwm->regs = devm_platform_ioremap_resource(pdev, 0);
  222. + if (IS_ERR(pwm->regs))
  223. + return dev_err_probe(dev, PTR_ERR(pwm->regs),
  224. + "Unable to map IO resources\n");
  225. +
  226. + pwm->clk = devm_clk_get(dev, NULL);
  227. + if (IS_ERR(pwm->clk))
  228. + return dev_err_probe(dev, PTR_ERR(pwm->clk),
  229. + "Unable to get pwm clock\n");
  230. +
  231. + pwm->rst = devm_reset_control_get_exclusive(dev, NULL);
  232. + if (IS_ERR(pwm->rst))
  233. + return dev_err_probe(dev, PTR_ERR(pwm->rst),
  234. + "Unable to get pwm reset\n");
  235. +
  236. + ret = clk_prepare_enable(pwm->clk);
  237. + if (ret) {
  238. + dev_err(dev,
  239. + "Failed to enable pwm clock, %d\n", ret);
  240. + return ret;
  241. + }
  242. +
  243. + reset_control_deassert(pwm->rst);
  244. +
  245. + pwm->approx_freq = (unsigned int)clk_get_rate(pwm->clk);
  246. + if (!pwm->approx_freq)
  247. + dev_err(dev, "get pwm apb clock rate failed.\n");
  248. +
  249. + ret = devm_pwmchip_add(dev, chip);
  250. + if (ret < 0) {
  251. + dev_err(dev, "cannot register PTC: %d\n", ret);
  252. + clk_disable_unprepare(pwm->clk);
  253. + return ret;
  254. + }
  255. +
  256. + platform_set_drvdata(pdev, pwm);
  257. +
  258. + return 0;
  259. +}
  260. +
  261. +static int starfive_pwm_ptc_remove(struct platform_device *dev)
  262. +{
  263. + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev);
  264. + struct pwm_chip *chip = &pwm->chip;
  265. +
  266. + pwmchip_remove(chip);
  267. +
  268. + return 0;
  269. +}
  270. +
  271. +static const struct of_device_id starfive_pwm_ptc_of_match[] = {
  272. + { .compatible = "starfive,jh7110-pwm" },
  273. + {},
  274. +};
  275. +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match);
  276. +
  277. +static struct platform_driver starfive_pwm_ptc_driver = {
  278. + .probe = starfive_pwm_ptc_probe,
  279. + .remove = starfive_pwm_ptc_remove,
  280. + .driver = {
  281. + .name = "pwm-starfive-ptc",
  282. + .of_match_table = starfive_pwm_ptc_of_match,
  283. + },
  284. +};
  285. +module_platform_driver(starfive_pwm_ptc_driver);
  286. +
  287. +MODULE_AUTHOR("Jenny Zhang <[email protected]>");
  288. +MODULE_AUTHOR("Hal Feng <[email protected]>");
  289. +MODULE_DESCRIPTION("StarFive PWM PTC driver");
  290. +MODULE_LICENSE("GPL");