]>
Commit | Line | Data |
---|---|---|
8ec6d935 JC |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify it | |
3 | * under the terms of the GNU General Public License version 2 as published | |
4 | * by the Free Software Foundation. | |
5 | * | |
6 | * Copyright (C) 2010 John Crispin <blogic@openwrt.org> | |
7 | */ | |
8 | ||
9 | #include <linux/slab.h> | |
4af92e7a | 10 | #include <linux/export.h> |
8ec6d935 JC |
11 | #include <linux/platform_device.h> |
12 | #include <linux/gpio.h> | |
13 | #include <linux/ioport.h> | |
14 | #include <linux/io.h> | |
15 | ||
16 | #include <lantiq_soc.h> | |
17 | ||
18 | #define LTQ_GPIO_OUT 0x00 | |
19 | #define LTQ_GPIO_IN 0x04 | |
20 | #define LTQ_GPIO_DIR 0x08 | |
21 | #define LTQ_GPIO_ALTSEL0 0x0C | |
22 | #define LTQ_GPIO_ALTSEL1 0x10 | |
23 | #define LTQ_GPIO_OD 0x14 | |
24 | ||
25 | #define PINS_PER_PORT 16 | |
26 | #define MAX_PORTS 3 | |
27 | ||
28 | #define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) | |
29 | #define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) | |
30 | #define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r) | |
31 | ||
32 | struct ltq_gpio { | |
33 | void __iomem *membase; | |
34 | struct gpio_chip chip; | |
35 | }; | |
36 | ||
37 | static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; | |
38 | ||
8ec6d935 JC |
39 | int ltq_gpio_request(unsigned int pin, unsigned int alt0, |
40 | unsigned int alt1, unsigned int dir, const char *name) | |
41 | { | |
42 | int id = 0; | |
43 | ||
44 | if (pin >= (MAX_PORTS * PINS_PER_PORT)) | |
45 | return -EINVAL; | |
46 | if (gpio_request(pin, name)) { | |
47 | pr_err("failed to setup lantiq gpio: %s\n", name); | |
48 | return -EBUSY; | |
49 | } | |
50 | if (dir) | |
51 | gpio_direction_output(pin, 1); | |
52 | else | |
53 | gpio_direction_input(pin); | |
54 | while (pin >= PINS_PER_PORT) { | |
55 | pin -= PINS_PER_PORT; | |
56 | id++; | |
57 | } | |
58 | if (alt0) | |
59 | ltq_gpio_setbit(ltq_gpio_port[id].membase, | |
60 | LTQ_GPIO_ALTSEL0, pin); | |
61 | else | |
62 | ltq_gpio_clearbit(ltq_gpio_port[id].membase, | |
63 | LTQ_GPIO_ALTSEL0, pin); | |
64 | if (alt1) | |
65 | ltq_gpio_setbit(ltq_gpio_port[id].membase, | |
66 | LTQ_GPIO_ALTSEL1, pin); | |
67 | else | |
68 | ltq_gpio_clearbit(ltq_gpio_port[id].membase, | |
69 | LTQ_GPIO_ALTSEL1, pin); | |
70 | return 0; | |
71 | } | |
72 | EXPORT_SYMBOL(ltq_gpio_request); | |
73 | ||
74 | static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) | |
75 | { | |
76 | struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); | |
77 | ||
78 | if (value) | |
79 | ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); | |
80 | else | |
81 | ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); | |
82 | } | |
83 | ||
84 | static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset) | |
85 | { | |
86 | struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); | |
87 | ||
88 | return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset); | |
89 | } | |
90 | ||
91 | static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) | |
92 | { | |
93 | struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); | |
94 | ||
95 | ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); | |
96 | ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | static int ltq_gpio_direction_output(struct gpio_chip *chip, | |
102 | unsigned int offset, int value) | |
103 | { | |
104 | struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); | |
105 | ||
106 | ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); | |
107 | ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); | |
108 | ltq_gpio_set(chip, offset, value); | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) | |
114 | { | |
115 | struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); | |
116 | ||
117 | ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); | |
118 | ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); | |
119 | return 0; | |
120 | } | |
121 | ||
122 | static int ltq_gpio_probe(struct platform_device *pdev) | |
123 | { | |
124 | struct resource *res; | |
125 | ||
126 | if (pdev->id >= MAX_PORTS) { | |
127 | dev_err(&pdev->dev, "invalid gpio port %d\n", | |
128 | pdev->id); | |
129 | return -EINVAL; | |
130 | } | |
131 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
132 | if (!res) { | |
133 | dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", | |
134 | pdev->id); | |
135 | return -ENOENT; | |
136 | } | |
137 | res = devm_request_mem_region(&pdev->dev, res->start, | |
138 | resource_size(res), dev_name(&pdev->dev)); | |
139 | if (!res) { | |
140 | dev_err(&pdev->dev, | |
141 | "failed to request memory for gpio port %d\n", | |
142 | pdev->id); | |
143 | return -EBUSY; | |
144 | } | |
145 | ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev, | |
146 | res->start, resource_size(res)); | |
147 | if (!ltq_gpio_port[pdev->id].membase) { | |
148 | dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n", | |
149 | pdev->id); | |
150 | return -ENOMEM; | |
151 | } | |
152 | ltq_gpio_port[pdev->id].chip.label = "ltq_gpio"; | |
153 | ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input; | |
154 | ltq_gpio_port[pdev->id].chip.direction_output = | |
155 | ltq_gpio_direction_output; | |
156 | ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get; | |
157 | ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; | |
158 | ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; | |
159 | ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; | |
160 | ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; | |
161 | platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); | |
162 | return gpiochip_add(<q_gpio_port[pdev->id].chip); | |
163 | } | |
164 | ||
165 | static struct platform_driver | |
166 | ltq_gpio_driver = { | |
167 | .probe = ltq_gpio_probe, | |
168 | .driver = { | |
169 | .name = "ltq_gpio", | |
170 | .owner = THIS_MODULE, | |
171 | }, | |
172 | }; | |
173 | ||
174 | int __init ltq_gpio_init(void) | |
175 | { | |
176 | int ret = platform_driver_register(<q_gpio_driver); | |
177 | ||
178 | if (ret) | |
6997991a | 179 | pr_info("ltq_gpio : Error registering platform driver!"); |
8ec6d935 JC |
180 | return ret; |
181 | } | |
182 | ||
183 | postcore_initcall(ltq_gpio_init); |