gpio-clps711x.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * CLPS711X GPIO driver
  3. *
  4. * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. */
  11. #include <linux/io.h>
  12. #include <linux/slab.h>
  13. #include <linux/gpio.h>
  14. #include <linux/module.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/platform_device.h>
  17. #include <mach/hardware.h>
  18. #define CLPS711X_GPIO_PORTS 5
  19. #define CLPS711X_GPIO_NAME "gpio-clps711x"
  20. struct clps711x_gpio {
  21. struct gpio_chip chip[CLPS711X_GPIO_PORTS];
  22. spinlock_t lock;
  23. };
  24. static void __iomem *clps711x_ports[] = {
  25. CLPS711X_VIRT_BASE + PADR,
  26. CLPS711X_VIRT_BASE + PBDR,
  27. CLPS711X_VIRT_BASE + PCDR,
  28. CLPS711X_VIRT_BASE + PDDR,
  29. CLPS711X_VIRT_BASE + PEDR,
  30. };
  31. static void __iomem *clps711x_pdirs[] = {
  32. CLPS711X_VIRT_BASE + PADDR,
  33. CLPS711X_VIRT_BASE + PBDDR,
  34. CLPS711X_VIRT_BASE + PCDDR,
  35. CLPS711X_VIRT_BASE + PDDDR,
  36. CLPS711X_VIRT_BASE + PEDDR,
  37. };
  38. #define clps711x_port(x) clps711x_ports[x->base / 8]
  39. #define clps711x_pdir(x) clps711x_pdirs[x->base / 8]
  40. static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
  41. {
  42. return !!readb(clps711x_port(chip)) & (1 << offset);
  43. }
  44. static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
  45. int value)
  46. {
  47. int tmp;
  48. unsigned long flags;
  49. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  50. spin_lock_irqsave(&gpio->lock, flags);
  51. tmp = readb(clps711x_port(chip)) & ~(1 << offset);
  52. if (value)
  53. tmp |= 1 << offset;
  54. writeb(tmp, clps711x_port(chip));
  55. spin_unlock_irqrestore(&gpio->lock, flags);
  56. }
  57. static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset)
  58. {
  59. int tmp;
  60. unsigned long flags;
  61. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  62. spin_lock_irqsave(&gpio->lock, flags);
  63. tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
  64. writeb(tmp, clps711x_pdir(chip));
  65. spin_unlock_irqrestore(&gpio->lock, flags);
  66. return 0;
  67. }
  68. static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset,
  69. int value)
  70. {
  71. int tmp;
  72. unsigned long flags;
  73. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  74. spin_lock_irqsave(&gpio->lock, flags);
  75. tmp = readb(clps711x_pdir(chip)) | (1 << offset);
  76. writeb(tmp, clps711x_pdir(chip));
  77. tmp = readb(clps711x_port(chip)) & ~(1 << offset);
  78. if (value)
  79. tmp |= 1 << offset;
  80. writeb(tmp, clps711x_port(chip));
  81. spin_unlock_irqrestore(&gpio->lock, flags);
  82. return 0;
  83. }
  84. struct clps711x_gpio_port {
  85. char *name;
  86. int nr;
  87. };
  88. static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = {
  89. { "PORTA", 8, },
  90. { "PORTB", 8, },
  91. { "PORTC", 8, },
  92. { "PORTD", 8, },
  93. { "PORTE", 3, },
  94. };
  95. static int __init gpio_clps711x_init(void)
  96. {
  97. int i;
  98. struct platform_device *pdev;
  99. struct clps711x_gpio *gpio;
  100. pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
  101. if (!pdev) {
  102. pr_err("Cannot create platform device: %s\n",
  103. CLPS711X_GPIO_NAME);
  104. return -ENOMEM;
  105. }
  106. platform_device_add(pdev);
  107. gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
  108. GFP_KERNEL);
  109. if (!gpio) {
  110. dev_err(&pdev->dev, "GPIO allocating memory error\n");
  111. platform_device_del(pdev);
  112. platform_device_put(pdev);
  113. return -ENOMEM;
  114. }
  115. platform_set_drvdata(pdev, gpio);
  116. spin_lock_init(&gpio->lock);
  117. for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
  118. gpio->chip[i].owner = THIS_MODULE;
  119. gpio->chip[i].dev = &pdev->dev;
  120. gpio->chip[i].label = clps711x_gpio_ports[i].name;
  121. gpio->chip[i].base = i * 8;
  122. gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
  123. gpio->chip[i].direction_input = gpio_clps711x_direction_in;
  124. gpio->chip[i].get = gpio_clps711x_get;
  125. gpio->chip[i].direction_output = gpio_clps711x_direction_out;
  126. gpio->chip[i].set = gpio_clps711x_set;
  127. WARN_ON(gpiochip_add(&gpio->chip[i]));
  128. }
  129. dev_info(&pdev->dev, "GPIO driver initialized\n");
  130. return 0;
  131. }
  132. arch_initcall(gpio_clps711x_init);
  133. MODULE_LICENSE("GPL v2");
  134. MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
  135. MODULE_DESCRIPTION("CLPS711X GPIO driver");