pm8916_gpio.c 7.7 KB

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