pm8916_gpio.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
  4. *
  5. * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
  6. */
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <power/pmic.h>
  10. #include <spmi/spmi.h>
  11. #include <asm/io.h>
  12. #include <asm/gpio.h>
  13. #include <linux/bitops.h>
  14. /* Register offset for each gpio */
  15. #define REG_OFFSET(x) ((x) * 0x100)
  16. /* Register maps */
  17. /* Type and subtype are shared for all pm8916 peripherals */
  18. #define REG_TYPE 0x4
  19. #define REG_SUBTYPE 0x5
  20. #define REG_STATUS 0x08
  21. #define REG_STATUS_VAL_MASK 0x1
  22. /* MODE_CTL */
  23. #define REG_CTL 0x40
  24. #define REG_CTL_MODE_MASK 0x70
  25. #define REG_CTL_MODE_INPUT 0x00
  26. #define REG_CTL_MODE_INOUT 0x20
  27. #define REG_CTL_MODE_OUTPUT 0x10
  28. #define REG_CTL_OUTPUT_MASK 0x0F
  29. #define REG_DIG_VIN_CTL 0x41
  30. #define REG_DIG_VIN_VIN0 0
  31. #define REG_DIG_PULL_CTL 0x42
  32. #define REG_DIG_PULL_NO_PU 0x5
  33. #define REG_DIG_OUT_CTL 0x45
  34. #define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
  35. #define REG_DIG_OUT_CTL_DRIVE_L 0x1
  36. #define REG_EN_CTL 0x46
  37. #define REG_EN_CTL_ENABLE (1 << 7)
  38. struct pm8916_gpio_bank {
  39. uint32_t pid; /* Peripheral ID on SPMI bus */
  40. };
  41. static int pm8916_gpio_set_direction(struct udevice *dev, unsigned offset,
  42. bool input, int value)
  43. {
  44. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  45. uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
  46. int ret;
  47. /* Disable the GPIO */
  48. ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL,
  49. REG_EN_CTL_ENABLE, 0);
  50. if (ret < 0)
  51. return ret;
  52. /* Select the mode */
  53. if (input)
  54. ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
  55. REG_CTL_MODE_INPUT);
  56. else
  57. ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL,
  58. REG_CTL_MODE_INOUT | (value ? 1 : 0));
  59. if (ret < 0)
  60. return ret;
  61. /* Set the right pull (no pull) */
  62. ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL,
  63. REG_DIG_PULL_NO_PU);
  64. if (ret < 0)
  65. return ret;
  66. /* Configure output pin drivers if needed */
  67. if (!input) {
  68. /* Select the VIN - VIN0, pin is input so it doesn't matter */
  69. ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL,
  70. REG_DIG_VIN_VIN0);
  71. if (ret < 0)
  72. return ret;
  73. /* Set the right dig out control */
  74. ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL,
  75. REG_DIG_OUT_CTL_CMOS |
  76. REG_DIG_OUT_CTL_DRIVE_L);
  77. if (ret < 0)
  78. return ret;
  79. }
  80. /* Enable the GPIO */
  81. return pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, 0,
  82. REG_EN_CTL_ENABLE);
  83. }
  84. static int pm8916_gpio_direction_input(struct udevice *dev, unsigned offset)
  85. {
  86. return pm8916_gpio_set_direction(dev, offset, true, 0);
  87. }
  88. static int pm8916_gpio_direction_output(struct udevice *dev, unsigned offset,
  89. int value)
  90. {
  91. return pm8916_gpio_set_direction(dev, offset, false, value);
  92. }
  93. static int pm8916_gpio_get_function(struct udevice *dev, unsigned offset)
  94. {
  95. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  96. uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
  97. int reg;
  98. /* Set the output value of the gpio */
  99. reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL);
  100. if (reg < 0)
  101. return reg;
  102. switch (reg & REG_CTL_MODE_MASK) {
  103. case REG_CTL_MODE_INPUT:
  104. return GPIOF_INPUT;
  105. case REG_CTL_MODE_INOUT: /* Fallthrough */
  106. case REG_CTL_MODE_OUTPUT:
  107. return GPIOF_OUTPUT;
  108. default:
  109. return GPIOF_UNKNOWN;
  110. }
  111. }
  112. static int pm8916_gpio_get_value(struct udevice *dev, unsigned offset)
  113. {
  114. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  115. uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
  116. int reg;
  117. reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS);
  118. if (reg < 0)
  119. return reg;
  120. return !!(reg & REG_STATUS_VAL_MASK);
  121. }
  122. static int pm8916_gpio_set_value(struct udevice *dev, unsigned offset,
  123. int value)
  124. {
  125. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  126. uint32_t gpio_base = priv->pid + REG_OFFSET(offset);
  127. /* Set the output value of the gpio */
  128. return pmic_clrsetbits(dev->parent, gpio_base + REG_CTL,
  129. REG_CTL_OUTPUT_MASK, !!value);
  130. }
  131. static const struct dm_gpio_ops pm8916_gpio_ops = {
  132. .direction_input = pm8916_gpio_direction_input,
  133. .direction_output = pm8916_gpio_direction_output,
  134. .get_value = pm8916_gpio_get_value,
  135. .set_value = pm8916_gpio_set_value,
  136. .get_function = pm8916_gpio_get_function,
  137. };
  138. static int pm8916_gpio_probe(struct udevice *dev)
  139. {
  140. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  141. int reg;
  142. priv->pid = dev_read_addr(dev);
  143. if (priv->pid == FDT_ADDR_T_NONE)
  144. return -EINVAL;
  145. /* Do a sanity check */
  146. reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
  147. if (reg != 0x10)
  148. return -ENODEV;
  149. reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
  150. if (reg != 0x5 && reg != 0x1)
  151. return -ENODEV;
  152. return 0;
  153. }
  154. static int pm8916_gpio_ofdata_to_platdata(struct udevice *dev)
  155. {
  156. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  157. uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 0);
  158. uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
  159. if (uc_priv->bank_name == NULL)
  160. uc_priv->bank_name = "pm8916";
  161. return 0;
  162. }
  163. static const struct udevice_id pm8916_gpio_ids[] = {
  164. { .compatible = "qcom,pm8916-gpio" },
  165. { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
  166. { }
  167. };
  168. U_BOOT_DRIVER(gpio_pm8916) = {
  169. .name = "gpio_pm8916",
  170. .id = UCLASS_GPIO,
  171. .of_match = pm8916_gpio_ids,
  172. .ofdata_to_platdata = pm8916_gpio_ofdata_to_platdata,
  173. .probe = pm8916_gpio_probe,
  174. .ops = &pm8916_gpio_ops,
  175. .priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank),
  176. };
  177. /* Add pmic buttons as GPIO as well - there is no generic way for now */
  178. #define PON_INT_RT_STS 0x10
  179. #define KPDPWR_ON_INT_BIT 0
  180. #define RESIN_ON_INT_BIT 1
  181. static int pm8941_pwrkey_get_function(struct udevice *dev, unsigned offset)
  182. {
  183. return GPIOF_INPUT;
  184. }
  185. static int pm8941_pwrkey_get_value(struct udevice *dev, unsigned offset)
  186. {
  187. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  188. int reg = pmic_reg_read(dev->parent, priv->pid + PON_INT_RT_STS);
  189. if (reg < 0)
  190. return 0;
  191. switch (offset) {
  192. case 0: /* Power button */
  193. return (reg & BIT(KPDPWR_ON_INT_BIT)) != 0;
  194. break;
  195. case 1: /* Reset button */
  196. default:
  197. return (reg & BIT(RESIN_ON_INT_BIT)) != 0;
  198. break;
  199. }
  200. }
  201. static const struct dm_gpio_ops pm8941_pwrkey_ops = {
  202. .get_value = pm8941_pwrkey_get_value,
  203. .get_function = pm8941_pwrkey_get_function,
  204. };
  205. static int pm8941_pwrkey_probe(struct udevice *dev)
  206. {
  207. struct pm8916_gpio_bank *priv = dev_get_priv(dev);
  208. int reg;
  209. priv->pid = devfdt_get_addr(dev);
  210. if (priv->pid == FDT_ADDR_T_NONE)
  211. return -EINVAL;
  212. /* Do a sanity check */
  213. reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE);
  214. if (reg != 0x1)
  215. return -ENODEV;
  216. reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE);
  217. if (reg != 0x1)
  218. return -ENODEV;
  219. return 0;
  220. }
  221. static int pm8941_pwrkey_ofdata_to_platdata(struct udevice *dev)
  222. {
  223. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  224. uc_priv->gpio_count = 2;
  225. uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
  226. if (uc_priv->bank_name == NULL)
  227. uc_priv->bank_name = "pm8916_key";
  228. return 0;
  229. }
  230. static const struct udevice_id pm8941_pwrkey_ids[] = {
  231. { .compatible = "qcom,pm8916-pwrkey" },
  232. { .compatible = "qcom,pm8994-pwrkey" },
  233. { }
  234. };
  235. U_BOOT_DRIVER(pwrkey_pm8941) = {
  236. .name = "pwrkey_pm8916",
  237. .id = UCLASS_GPIO,
  238. .of_match = pm8941_pwrkey_ids,
  239. .ofdata_to_platdata = pm8941_pwrkey_ofdata_to_platdata,
  240. .probe = pm8941_pwrkey_probe,
  241. .ops = &pm8941_pwrkey_ops,
  242. .priv_auto_alloc_size = sizeof(struct pm8916_gpio_bank),
  243. };