pm8916_gpio.c 7.4 KB

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