gpio-da9055.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * GPIO Driver for Dialog DA9055 PMICs.
  3. *
  4. * Copyright(c) 2012 Dialog Semiconductor Ltd.
  5. *
  6. * Author: David Dajun Chen <dchen@diasemi.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. */
  14. #include <linux/module.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/gpio.h>
  17. #include <linux/mfd/da9055/core.h>
  18. #include <linux/mfd/da9055/reg.h>
  19. #include <linux/mfd/da9055/pdata.h>
  20. #define DA9055_VDD_IO 0x0
  21. #define DA9055_PUSH_PULL 0x3
  22. #define DA9055_ACT_LOW 0x0
  23. #define DA9055_GPI 0x1
  24. #define DA9055_PORT_MASK 0x3
  25. #define DA9055_PORT_SHIFT(offset) (4 * (offset % 2))
  26. #define DA9055_INPUT DA9055_GPI
  27. #define DA9055_OUTPUT DA9055_PUSH_PULL
  28. #define DA9055_IRQ_GPI0 3
  29. struct da9055_gpio {
  30. struct da9055 *da9055;
  31. struct gpio_chip gp;
  32. };
  33. static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
  34. {
  35. return container_of(chip, struct da9055_gpio, gp);
  36. }
  37. static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
  38. {
  39. struct da9055_gpio *gpio = to_da9055_gpio(gc);
  40. int gpio_direction = 0;
  41. int ret;
  42. /* Get GPIO direction */
  43. ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1);
  44. if (ret < 0)
  45. return ret;
  46. gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset);
  47. gpio_direction >>= DA9055_PORT_SHIFT(offset);
  48. switch (gpio_direction) {
  49. case DA9055_INPUT:
  50. ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B);
  51. if (ret < 0)
  52. return ret;
  53. break;
  54. case DA9055_OUTPUT:
  55. ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2);
  56. if (ret < 0)
  57. return ret;
  58. }
  59. return ret & (1 << offset);
  60. }
  61. static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
  62. {
  63. struct da9055_gpio *gpio = to_da9055_gpio(gc);
  64. da9055_reg_update(gpio->da9055,
  65. DA9055_REG_GPIO_MODE0_2,
  66. 1 << offset,
  67. value << offset);
  68. }
  69. static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
  70. {
  71. struct da9055_gpio *gpio = to_da9055_gpio(gc);
  72. unsigned char reg_byte;
  73. reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
  74. << DA9055_PORT_SHIFT(offset);
  75. return da9055_reg_update(gpio->da9055, (offset >> 1) +
  76. DA9055_REG_GPIO0_1,
  77. DA9055_PORT_MASK <<
  78. DA9055_PORT_SHIFT(offset),
  79. reg_byte);
  80. }
  81. static int da9055_gpio_direction_output(struct gpio_chip *gc,
  82. unsigned offset, int value)
  83. {
  84. struct da9055_gpio *gpio = to_da9055_gpio(gc);
  85. unsigned char reg_byte;
  86. int ret;
  87. reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL)
  88. << DA9055_PORT_SHIFT(offset);
  89. ret = da9055_reg_update(gpio->da9055, (offset >> 1) +
  90. DA9055_REG_GPIO0_1,
  91. DA9055_PORT_MASK <<
  92. DA9055_PORT_SHIFT(offset),
  93. reg_byte);
  94. if (ret < 0)
  95. return ret;
  96. da9055_gpio_set(gc, offset, value);
  97. return 0;
  98. }
  99. static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
  100. {
  101. struct da9055_gpio *gpio = to_da9055_gpio(gc);
  102. struct da9055 *da9055 = gpio->da9055;
  103. return regmap_irq_get_virq(da9055->irq_data,
  104. DA9055_IRQ_GPI0 + offset);
  105. }
  106. static struct gpio_chip reference_gp = {
  107. .label = "da9055-gpio",
  108. .owner = THIS_MODULE,
  109. .get = da9055_gpio_get,
  110. .set = da9055_gpio_set,
  111. .direction_input = da9055_gpio_direction_input,
  112. .direction_output = da9055_gpio_direction_output,
  113. .to_irq = da9055_gpio_to_irq,
  114. .can_sleep = true,
  115. .ngpio = 3,
  116. .base = -1,
  117. };
  118. static int da9055_gpio_probe(struct platform_device *pdev)
  119. {
  120. struct da9055_gpio *gpio;
  121. struct da9055_pdata *pdata;
  122. int ret;
  123. gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
  124. if (!gpio)
  125. return -ENOMEM;
  126. gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
  127. pdata = dev_get_platdata(gpio->da9055->dev);
  128. gpio->gp = reference_gp;
  129. if (pdata && pdata->gpio_base)
  130. gpio->gp.base = pdata->gpio_base;
  131. ret = gpiochip_add(&gpio->gp);
  132. if (ret < 0) {
  133. dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
  134. goto err_mem;
  135. }
  136. platform_set_drvdata(pdev, gpio);
  137. return 0;
  138. err_mem:
  139. return ret;
  140. }
  141. static int da9055_gpio_remove(struct platform_device *pdev)
  142. {
  143. struct da9055_gpio *gpio = platform_get_drvdata(pdev);
  144. gpiochip_remove(&gpio->gp);
  145. return 0;
  146. }
  147. static struct platform_driver da9055_gpio_driver = {
  148. .probe = da9055_gpio_probe,
  149. .remove = da9055_gpio_remove,
  150. .driver = {
  151. .name = "da9055-gpio",
  152. },
  153. };
  154. static int __init da9055_gpio_init(void)
  155. {
  156. return platform_driver_register(&da9055_gpio_driver);
  157. }
  158. subsys_initcall(da9055_gpio_init);
  159. static void __exit da9055_gpio_exit(void)
  160. {
  161. platform_driver_unregister(&da9055_gpio_driver);
  162. }
  163. module_exit(da9055_gpio_exit);
  164. MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
  165. MODULE_DESCRIPTION("DA9055 GPIO Device Driver");
  166. MODULE_LICENSE("GPL");
  167. MODULE_ALIAS("platform:da9055-gpio");