Commit d92c7962470b699ef7a697524b9a679846e9e15b
Committed by
Kevin Hilman
1 parent
4d1e78480c
Exists in
master
and in
39 other branches
Davinci: tnetv107x initial gpio support
This patch adds support for the tnetv107x gpio controller. Key differences between davinci and tnetv107x controllers: - register map - davinci's controller is organized into banks of 32 gpios, tnetv107x has a single space with arrays of registers for in, out, direction, etc. - davinci's controller has separate set/clear registers for output, tnetv107x has a single direct mapped register. This patch does not yet add gpio irq support on this controller. Signed-off-by: Cyril Chemparathy <cyril@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Showing 3 changed files with 221 additions and 7 deletions Side-by-side Diff
arch/arm/mach-davinci/Makefile
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o |
18 | 18 | obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o |
19 | 19 | obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += tnetv107x.o devices-tnetv107x.o |
20 | +obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o | |
20 | 21 | |
21 | 22 | obj-$(CONFIG_AINTC) += irq.o |
22 | 23 | obj-$(CONFIG_CP_INTC) += cp_intc.o |
arch/arm/mach-davinci/gpio-tnetv107x.c
1 | +/* | |
2 | + * Texas Instruments TNETV107X GPIO Controller | |
3 | + * | |
4 | + * Copyright (C) 2010 Texas Instruments | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License as | |
8 | + * published by the Free Software Foundation version 2. | |
9 | + * | |
10 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
11 | + * kind, whether express or implied; without even the implied warranty | |
12 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | + * GNU General Public License for more details. | |
14 | + */ | |
15 | +#include <linux/kernel.h> | |
16 | +#include <linux/init.h> | |
17 | +#include <linux/gpio.h> | |
18 | + | |
19 | +#include <mach/common.h> | |
20 | +#include <mach/tnetv107x.h> | |
21 | + | |
22 | +struct tnetv107x_gpio_regs { | |
23 | + u32 idver; | |
24 | + u32 data_in[3]; | |
25 | + u32 data_out[3]; | |
26 | + u32 direction[3]; | |
27 | + u32 enable[3]; | |
28 | +}; | |
29 | + | |
30 | +#define gpio_reg_index(gpio) ((gpio) >> 5) | |
31 | +#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f) | |
32 | + | |
33 | +#define gpio_reg_rmw(reg, mask, val) \ | |
34 | + __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg)) | |
35 | + | |
36 | +#define gpio_reg_set_bit(reg, gpio) \ | |
37 | + gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio)) | |
38 | + | |
39 | +#define gpio_reg_clear_bit(reg, gpio) \ | |
40 | + gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0) | |
41 | + | |
42 | +#define gpio_reg_get_bit(reg, gpio) \ | |
43 | + (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio)) | |
44 | + | |
45 | +#define chip2controller(chip) \ | |
46 | + container_of(chip, struct davinci_gpio_controller, chip) | |
47 | + | |
48 | +#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32) | |
49 | + | |
50 | +static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS]; | |
51 | + | |
52 | +static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) | |
53 | +{ | |
54 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
55 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
56 | + unsigned gpio = chip->base + offset; | |
57 | + unsigned long flags; | |
58 | + | |
59 | + spin_lock_irqsave(&ctlr->lock, flags); | |
60 | + | |
61 | + gpio_reg_set_bit(®s->enable, gpio); | |
62 | + | |
63 | + spin_unlock_irqrestore(&ctlr->lock, flags); | |
64 | + | |
65 | + return 0; | |
66 | +} | |
67 | + | |
68 | +static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) | |
69 | +{ | |
70 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
71 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
72 | + unsigned gpio = chip->base + offset; | |
73 | + unsigned long flags; | |
74 | + | |
75 | + spin_lock_irqsave(&ctlr->lock, flags); | |
76 | + | |
77 | + gpio_reg_clear_bit(®s->enable, gpio); | |
78 | + | |
79 | + spin_unlock_irqrestore(&ctlr->lock, flags); | |
80 | +} | |
81 | + | |
82 | +static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) | |
83 | +{ | |
84 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
85 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
86 | + unsigned gpio = chip->base + offset; | |
87 | + unsigned long flags; | |
88 | + | |
89 | + spin_lock_irqsave(&ctlr->lock, flags); | |
90 | + | |
91 | + gpio_reg_set_bit(®s->direction, gpio); | |
92 | + | |
93 | + spin_unlock_irqrestore(&ctlr->lock, flags); | |
94 | + | |
95 | + return 0; | |
96 | +} | |
97 | + | |
98 | +static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, | |
99 | + unsigned offset, int value) | |
100 | +{ | |
101 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
102 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
103 | + unsigned gpio = chip->base + offset; | |
104 | + unsigned long flags; | |
105 | + | |
106 | + spin_lock_irqsave(&ctlr->lock, flags); | |
107 | + | |
108 | + if (value) | |
109 | + gpio_reg_set_bit(®s->data_out, gpio); | |
110 | + else | |
111 | + gpio_reg_clear_bit(®s->data_out, gpio); | |
112 | + | |
113 | + gpio_reg_clear_bit(®s->direction, gpio); | |
114 | + | |
115 | + spin_unlock_irqrestore(&ctlr->lock, flags); | |
116 | + | |
117 | + return 0; | |
118 | +} | |
119 | + | |
120 | +static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) | |
121 | +{ | |
122 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
123 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
124 | + unsigned gpio = chip->base + offset; | |
125 | + int ret; | |
126 | + | |
127 | + ret = gpio_reg_get_bit(®s->data_in, gpio); | |
128 | + | |
129 | + return ret ? 1 : 0; | |
130 | +} | |
131 | + | |
132 | +static void tnetv107x_gpio_set(struct gpio_chip *chip, | |
133 | + unsigned offset, int value) | |
134 | +{ | |
135 | + struct davinci_gpio_controller *ctlr = chip2controller(chip); | |
136 | + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; | |
137 | + unsigned gpio = chip->base + offset; | |
138 | + unsigned long flags; | |
139 | + | |
140 | + spin_lock_irqsave(&ctlr->lock, flags); | |
141 | + | |
142 | + if (value) | |
143 | + gpio_reg_set_bit(®s->data_out, gpio); | |
144 | + else | |
145 | + gpio_reg_clear_bit(®s->data_out, gpio); | |
146 | + | |
147 | + spin_unlock_irqrestore(&ctlr->lock, flags); | |
148 | +} | |
149 | + | |
150 | +static int __init tnetv107x_gpio_setup(void) | |
151 | +{ | |
152 | + int i, base; | |
153 | + unsigned ngpio; | |
154 | + struct davinci_soc_info *soc_info = &davinci_soc_info; | |
155 | + struct tnetv107x_gpio_regs *regs; | |
156 | + struct davinci_gpio_controller *ctlr; | |
157 | + | |
158 | + if (soc_info->gpio_type != GPIO_TYPE_TNETV107X) | |
159 | + return 0; | |
160 | + | |
161 | + ngpio = soc_info->gpio_num; | |
162 | + if (ngpio == 0) { | |
163 | + pr_err("GPIO setup: how many GPIOs?\n"); | |
164 | + return -EINVAL; | |
165 | + } | |
166 | + | |
167 | + if (WARN_ON(TNETV107X_N_GPIO < ngpio)) | |
168 | + ngpio = TNETV107X_N_GPIO; | |
169 | + | |
170 | + regs = ioremap(soc_info->gpio_base, SZ_4K); | |
171 | + if (WARN_ON(!regs)) | |
172 | + return -EINVAL; | |
173 | + | |
174 | + for (i = 0, base = 0; base < ngpio; i++, base += 32) { | |
175 | + ctlr = &chips[i]; | |
176 | + | |
177 | + ctlr->chip.label = "tnetv107x"; | |
178 | + ctlr->chip.can_sleep = 0; | |
179 | + ctlr->chip.base = base; | |
180 | + ctlr->chip.ngpio = ngpio - base; | |
181 | + if (ctlr->chip.ngpio > 32) | |
182 | + ctlr->chip.ngpio = 32; | |
183 | + | |
184 | + ctlr->chip.request = tnetv107x_gpio_request; | |
185 | + ctlr->chip.free = tnetv107x_gpio_free; | |
186 | + ctlr->chip.direction_input = tnetv107x_gpio_dir_in; | |
187 | + ctlr->chip.get = tnetv107x_gpio_get; | |
188 | + ctlr->chip.direction_output = tnetv107x_gpio_dir_out; | |
189 | + ctlr->chip.set = tnetv107x_gpio_set; | |
190 | + | |
191 | + spin_lock_init(&ctlr->lock); | |
192 | + | |
193 | + ctlr->regs = regs; | |
194 | + ctlr->set_data = ®s->data_out[i]; | |
195 | + ctlr->clr_data = ®s->data_out[i]; | |
196 | + ctlr->in_data = ®s->data_in[i]; | |
197 | + | |
198 | + gpiochip_add(&ctlr->chip); | |
199 | + } | |
200 | + | |
201 | + soc_info->gpio_ctlrs = chips; | |
202 | + soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); | |
203 | + return 0; | |
204 | +} | |
205 | +pure_initcall(tnetv107x_gpio_setup); |
arch/arm/mach-davinci/include/mach/gpio.h
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | |
26 | 26 | enum davinci_gpio_type { |
27 | 27 | GPIO_TYPE_DAVINCI = 0, |
28 | + GPIO_TYPE_TNETV107X, | |
28 | 29 | }; |
29 | 30 | |
30 | 31 | /* |
31 | 32 | |
... | ... | @@ -87,9 +88,13 @@ |
87 | 88 | return 1 << (gpio % 32); |
88 | 89 | } |
89 | 90 | |
90 | -/* The get/set/clear functions will inline when called with constant | |
91 | +/* | |
92 | + * The get/set/clear functions will inline when called with constant | |
91 | 93 | * parameters referencing built-in GPIOs, for low-overhead bitbanging. |
92 | 94 | * |
95 | + * gpio_set_value() will inline only on traditional Davinci style controllers | |
96 | + * with distinct set/clear registers. | |
97 | + * | |
93 | 98 | * Otherwise, calls with variable parameters or referencing external |
94 | 99 | * GPIOs (e.g. on GPIO expander chips) use outlined functions. |
95 | 100 | */ |
... | ... | @@ -100,12 +105,15 @@ |
100 | 105 | u32 mask; |
101 | 106 | |
102 | 107 | ctlr = __gpio_to_controller(gpio); |
103 | - mask = __gpio_mask(gpio); | |
104 | - if (value) | |
105 | - __raw_writel(mask, ctlr->set_data); | |
106 | - else | |
107 | - __raw_writel(mask, ctlr->clr_data); | |
108 | - return; | |
108 | + | |
109 | + if (ctlr->set_data != ctlr->clr_data) { | |
110 | + mask = __gpio_mask(gpio); | |
111 | + if (value) | |
112 | + __raw_writel(mask, ctlr->set_data); | |
113 | + else | |
114 | + __raw_writel(mask, ctlr->clr_data); | |
115 | + return; | |
116 | + } | |
109 | 117 | } |
110 | 118 | |
111 | 119 | __gpio_set_value(gpio, value); |