msm: gpio: Add v2 gpio support to MSM SoCs.
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / arch / arm / mach-msm / gpio-v2.c
CommitLineData
0cc2fc1f
GB
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 *
17 */
18#include <linux/gpio.h>
19#include <linux/io.h>
20#include <linux/irq.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/spinlock.h>
24#include <mach/msm_iomap.h>
25#include "gpiomux.h"
26
27/* Bits of interest in the GPIO_IN_OUT register.
28 */
29enum {
30 GPIO_IN_BIT = 0,
31 GPIO_OUT_BIT = 1
32};
33
34/* Bits of interest in the GPIO_CFG register.
35 */
36enum {
37 GPIO_OE_BIT = 9,
38};
39
40#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
41#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
42
43static DEFINE_SPINLOCK(tlmm_lock);
44
45static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
46{
47 return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
48}
49
50static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
51{
52 writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
53}
54
55static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
56{
57 unsigned long irq_flags;
58
59 spin_lock_irqsave(&tlmm_lock, irq_flags);
60 writel(readl(GPIO_CONFIG(offset)) & ~BIT(GPIO_OE_BIT),
61 GPIO_CONFIG(offset));
62 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
63 return 0;
64}
65
66static int msm_gpio_direction_output(struct gpio_chip *chip,
67 unsigned offset,
68 int val)
69{
70 unsigned long irq_flags;
71
72 spin_lock_irqsave(&tlmm_lock, irq_flags);
73 msm_gpio_set(chip, offset, val);
74 writel(readl(GPIO_CONFIG(offset)) | BIT(GPIO_OE_BIT),
75 GPIO_CONFIG(offset));
76 spin_unlock_irqrestore(&tlmm_lock, irq_flags);
77 return 0;
78}
79
80static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
81{
82 return msm_gpiomux_get(chip->base + offset);
83}
84
85static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
86{
87 msm_gpiomux_put(chip->base + offset);
88}
89
90static struct gpio_chip msm_gpio = {
91 .base = 0,
92 .ngpio = NR_GPIO_IRQS,
93 .direction_input = msm_gpio_direction_input,
94 .direction_output = msm_gpio_direction_output,
95 .get = msm_gpio_get,
96 .set = msm_gpio_set,
97 .request = msm_gpio_request,
98 .free = msm_gpio_free,
99};
100
101static int __devinit msm_gpio_probe(struct platform_device *dev)
102{
103 int ret;
104
105 msm_gpio.label = dev->name;
106 ret = gpiochip_add(&msm_gpio);
107
108 return ret;
109}
110
111static int __devexit msm_gpio_remove(struct platform_device *dev)
112{
113 int ret = gpiochip_remove(&msm_gpio);
114
115 if (ret < 0)
116 return ret;
117
118 set_irq_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
119
120 return 0;
121}
122
123static struct platform_driver msm_gpio_driver = {
124 .probe = msm_gpio_probe,
125 .remove = __devexit_p(msm_gpio_remove),
126 .driver = {
127 .name = "msmgpio",
128 .owner = THIS_MODULE,
129 },
130};
131
132static struct platform_device msm_device_gpio = {
133 .name = "msmgpio",
134 .id = -1,
135};
136
137static int __init msm_gpio_init(void)
138{
139 int rc;
140
141 rc = platform_driver_register(&msm_gpio_driver);
142 if (!rc) {
143 rc = platform_device_register(&msm_device_gpio);
144 if (rc)
145 platform_driver_unregister(&msm_gpio_driver);
146 }
147
148 return rc;
149}
150
151static void __exit msm_gpio_exit(void)
152{
153 platform_device_unregister(&msm_device_gpio);
154 platform_driver_unregister(&msm_gpio_driver);
155}
156
157postcore_initcall(msm_gpio_init);
158module_exit(msm_gpio_exit);
159
160MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
161MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
162MODULE_LICENSE("GPL v2");
163MODULE_ALIAS("platform:msmgpio");