tps6594-pfsm.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * PFSM (Pre-configurable Finite State Machine) driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs
  4. *
  5. * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
  6. */
  7. #include <linux/errno.h>
  8. #include <linux/fs.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/ioctl.h>
  11. #include <linux/miscdevice.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/regmap.h>
  15. #include <linux/mfd/tps6594.h>
  16. #include <linux/tps6594_pfsm.h>
  17. #define TPS6594_STARTUP_DEST_MCU_ONLY_VAL 2
  18. #define TPS6594_STARTUP_DEST_ACTIVE_VAL 3
  19. #define TPS6594_STARTUP_DEST_SHIFT 5
  20. #define TPS6594_STARTUP_DEST_MCU_ONLY (TPS6594_STARTUP_DEST_MCU_ONLY_VAL \
  21. << TPS6594_STARTUP_DEST_SHIFT)
  22. #define TPS6594_STARTUP_DEST_ACTIVE (TPS6594_STARTUP_DEST_ACTIVE_VAL \
  23. << TPS6594_STARTUP_DEST_SHIFT)
  24. /*
  25. * To update the PMIC firmware, the user must be able to access
  26. * page 0 (user registers) and page 1 (NVM control and configuration).
  27. */
  28. #define TPS6594_PMIC_MAX_POS 0x200
  29. #define TPS6594_FILE_TO_PFSM(f) container_of((f)->private_data, struct tps6594_pfsm, miscdev)
  30. /**
  31. * struct tps6594_pfsm - device private data structure
  32. *
  33. * @miscdev: misc device infos
  34. * @regmap: regmap for accessing the device registers
  35. * @chip_id: chip identifier of the device
  36. */
  37. struct tps6594_pfsm {
  38. struct miscdevice miscdev;
  39. struct regmap *regmap;
  40. unsigned long chip_id;
  41. };
  42. static ssize_t tps6594_pfsm_read(struct file *f, char __user *buf,
  43. size_t count, loff_t *ppos)
  44. {
  45. struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
  46. loff_t pos = *ppos;
  47. unsigned int val;
  48. int ret;
  49. int i;
  50. if (pos < 0)
  51. return -EINVAL;
  52. if (pos >= TPS6594_PMIC_MAX_POS)
  53. return 0;
  54. if (count > TPS6594_PMIC_MAX_POS - pos)
  55. count = TPS6594_PMIC_MAX_POS - pos;
  56. for (i = 0 ; i < count ; i++) {
  57. ret = regmap_read(pfsm->regmap, pos + i, &val);
  58. if (ret)
  59. return ret;
  60. if (put_user(val, buf + i))
  61. return -EFAULT;
  62. }
  63. *ppos = pos + count;
  64. return count;
  65. }
  66. static ssize_t tps6594_pfsm_write(struct file *f, const char __user *buf,
  67. size_t count, loff_t *ppos)
  68. {
  69. struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
  70. loff_t pos = *ppos;
  71. char val;
  72. int ret;
  73. int i;
  74. if (pos < 0)
  75. return -EINVAL;
  76. if (pos >= TPS6594_PMIC_MAX_POS || !count)
  77. return 0;
  78. if (count > TPS6594_PMIC_MAX_POS - pos)
  79. count = TPS6594_PMIC_MAX_POS - pos;
  80. for (i = 0 ; i < count ; i++) {
  81. if (get_user(val, buf + i))
  82. return -EFAULT;
  83. ret = regmap_write(pfsm->regmap, pos + i, val);
  84. if (ret)
  85. return ret;
  86. }
  87. *ppos = pos + count;
  88. return count;
  89. }
  90. static int tps6594_pfsm_configure_ret_trig(struct regmap *regmap, u8 gpio_ret, u8 ddr_ret)
  91. {
  92. int ret;
  93. if (gpio_ret)
  94. ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  95. TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
  96. else
  97. ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  98. TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
  99. if (ret)
  100. return ret;
  101. if (ddr_ret)
  102. ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  103. TPS6594_BIT_TRIGGER_I2C(7));
  104. else
  105. ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  106. TPS6594_BIT_TRIGGER_I2C(7));
  107. return ret;
  108. }
  109. static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
  110. {
  111. struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
  112. struct pmic_state_opt state_opt;
  113. void __user *argp = (void __user *)arg;
  114. unsigned int regmap_reg, mask;
  115. int ret = -ENOIOCTLCMD;
  116. switch (cmd) {
  117. case PMIC_GOTO_STANDBY:
  118. /* Disable LP mode on TPS6594 Family PMIC */
  119. if (pfsm->chip_id != TPS65224) {
  120. ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
  121. TPS6594_BIT_LP_STANDBY_SEL);
  122. if (ret)
  123. return ret;
  124. }
  125. /* Force trigger */
  126. ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  127. TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
  128. break;
  129. case PMIC_GOTO_LP_STANDBY:
  130. /* TPS65224 does not support LP STANDBY */
  131. if (pfsm->chip_id == TPS65224)
  132. return ret;
  133. /* Enable LP mode */
  134. ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
  135. TPS6594_BIT_LP_STANDBY_SEL);
  136. if (ret)
  137. return ret;
  138. /* Force trigger */
  139. ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  140. TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
  141. break;
  142. case PMIC_UPDATE_PGM:
  143. /* Force trigger */
  144. ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
  145. TPS6594_BIT_TRIGGER_I2C(3), TPS6594_BIT_TRIGGER_I2C(3));
  146. break;
  147. case PMIC_SET_ACTIVE_STATE:
  148. /* Modify NSLEEP1-2 bits */
  149. ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
  150. TPS6594_BIT_NSLEEP1B | TPS6594_BIT_NSLEEP2B);
  151. break;
  152. case PMIC_SET_MCU_ONLY_STATE:
  153. /* TPS65224 does not support MCU_ONLY_STATE */
  154. if (pfsm->chip_id == TPS65224)
  155. return ret;
  156. if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
  157. return -EFAULT;
  158. /* Configure retention triggers */
  159. ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
  160. state_opt.ddr_retention);
  161. if (ret)
  162. return ret;
  163. /* Modify NSLEEP1-2 bits */
  164. ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
  165. TPS6594_BIT_NSLEEP1B);
  166. if (ret)
  167. return ret;
  168. ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
  169. TPS6594_BIT_NSLEEP2B);
  170. break;
  171. case PMIC_SET_RETENTION_STATE:
  172. if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
  173. return -EFAULT;
  174. /* Configure wake-up destination */
  175. if (pfsm->chip_id == TPS65224) {
  176. regmap_reg = TPS65224_REG_STARTUP_CTRL;
  177. mask = TPS65224_MASK_STARTUP_DEST;
  178. } else {
  179. regmap_reg = TPS6594_REG_RTC_CTRL_2;
  180. mask = TPS6594_MASK_STARTUP_DEST;
  181. }
  182. if (state_opt.mcu_only_startup_dest)
  183. ret = regmap_write_bits(pfsm->regmap, regmap_reg,
  184. mask, TPS6594_STARTUP_DEST_MCU_ONLY);
  185. else
  186. ret = regmap_write_bits(pfsm->regmap, regmap_reg,
  187. mask, TPS6594_STARTUP_DEST_ACTIVE);
  188. if (ret)
  189. return ret;
  190. /* Configure retention triggers */
  191. ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
  192. state_opt.ddr_retention);
  193. if (ret)
  194. return ret;
  195. /* Modify NSLEEP1-2 bits */
  196. ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
  197. pfsm->chip_id == TPS65224 ?
  198. TPS6594_BIT_NSLEEP1B : TPS6594_BIT_NSLEEP2B);
  199. break;
  200. }
  201. return ret;
  202. }
  203. static const struct file_operations tps6594_pfsm_fops = {
  204. .owner = THIS_MODULE,
  205. .llseek = generic_file_llseek,
  206. .read = tps6594_pfsm_read,
  207. .write = tps6594_pfsm_write,
  208. .unlocked_ioctl = tps6594_pfsm_ioctl,
  209. .compat_ioctl = compat_ptr_ioctl,
  210. };
  211. static irqreturn_t tps6594_pfsm_isr(int irq, void *dev_id)
  212. {
  213. struct platform_device *pdev = dev_id;
  214. int i;
  215. for (i = 0 ; i < pdev->num_resources ; i++) {
  216. if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
  217. dev_err(pdev->dev.parent, "%s event detected\n", pdev->resource[i].name);
  218. return IRQ_HANDLED;
  219. }
  220. }
  221. return IRQ_NONE;
  222. }
  223. static int tps6594_pfsm_probe(struct platform_device *pdev)
  224. {
  225. struct tps6594_pfsm *pfsm;
  226. struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
  227. struct device *dev = &pdev->dev;
  228. int irq;
  229. int ret;
  230. int i;
  231. pfsm = devm_kzalloc(dev, sizeof(struct tps6594_pfsm), GFP_KERNEL);
  232. if (!pfsm)
  233. return -ENOMEM;
  234. pfsm->regmap = tps->regmap;
  235. pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
  236. pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
  237. tps->chip_id, tps->reg);
  238. pfsm->miscdev.fops = &tps6594_pfsm_fops;
  239. pfsm->miscdev.parent = dev->parent;
  240. pfsm->chip_id = tps->chip_id;
  241. for (i = 0 ; i < pdev->num_resources ; i++) {
  242. irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
  243. if (irq < 0)
  244. return irq;
  245. ret = devm_request_threaded_irq(dev, irq, NULL,
  246. tps6594_pfsm_isr, IRQF_ONESHOT,
  247. pdev->resource[i].name, pdev);
  248. if (ret)
  249. return dev_err_probe(dev, ret, "Failed to request irq\n");
  250. }
  251. platform_set_drvdata(pdev, pfsm);
  252. return misc_register(&pfsm->miscdev);
  253. }
  254. static void tps6594_pfsm_remove(struct platform_device *pdev)
  255. {
  256. struct tps6594_pfsm *pfsm = platform_get_drvdata(pdev);
  257. misc_deregister(&pfsm->miscdev);
  258. }
  259. static struct platform_driver tps6594_pfsm_driver = {
  260. .driver = {
  261. .name = "tps6594-pfsm",
  262. },
  263. .probe = tps6594_pfsm_probe,
  264. .remove_new = tps6594_pfsm_remove,
  265. };
  266. module_platform_driver(tps6594_pfsm_driver);
  267. MODULE_ALIAS("platform:tps6594-pfsm");
  268. MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
  269. MODULE_DESCRIPTION("TPS6594 Pre-configurable Finite State Machine Driver");
  270. MODULE_LICENSE("GPL");