diff options
Diffstat (limited to 'drivers/tty/serial/max3107-aava.c')
-rw-r--r-- | drivers/tty/serial/max3107-aava.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c new file mode 100644 index 000000000000..a1fe304f2f52 --- /dev/null +++ b/drivers/tty/serial/max3107-aava.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * max3107.c - spi uart protocol driver for Maxim 3107 | ||
3 | * Based on max3100.c | ||
4 | * by Christian Pellegrin <chripell@evolware.org> | ||
5 | * and max3110.c | ||
6 | * by Feng Tang <feng.tang@intel.com> | ||
7 | * | ||
8 | * Copyright (C) Aavamobile 2009 | ||
9 | * | ||
10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include <linux/delay.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/serial_core.h> | ||
33 | #include <linux/serial.h> | ||
34 | #include <linux/spi/spi.h> | ||
35 | #include <linux/freezer.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/gpio.h> | ||
38 | #include <linux/sfi.h> | ||
39 | #include <asm/mrst.h> | ||
40 | #include "max3107.h" | ||
41 | |||
42 | /* GPIO direction to input function */ | ||
43 | static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | ||
44 | { | ||
45 | struct max3107_port *s = container_of(chip, struct max3107_port, chip); | ||
46 | u16 buf[1]; /* Buffer for SPI transfer */ | ||
47 | |||
48 | if (offset >= MAX3107_GPIO_COUNT) { | ||
49 | dev_err(&s->spi->dev, "Invalid GPIO\n"); | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | |||
53 | /* Read current GPIO configuration register */ | ||
54 | buf[0] = MAX3107_GPIOCFG_REG; | ||
55 | /* Perform SPI transfer */ | ||
56 | if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { | ||
57 | dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n"); | ||
58 | return -EIO; | ||
59 | } | ||
60 | buf[0] &= MAX3107_SPI_RX_DATA_MASK; | ||
61 | |||
62 | /* Set GPIO to input */ | ||
63 | buf[0] &= ~(0x0001 << offset); | ||
64 | |||
65 | /* Write new GPIO configuration register value */ | ||
66 | buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); | ||
67 | /* Perform SPI transfer */ | ||
68 | if (max3107_rw(s, (u8 *)buf, NULL, 2)) { | ||
69 | dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n"); | ||
70 | return -EIO; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* GPIO direction to output function */ | ||
76 | static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset, | ||
77 | int value) | ||
78 | { | ||
79 | struct max3107_port *s = container_of(chip, struct max3107_port, chip); | ||
80 | u16 buf[2]; /* Buffer for SPI transfers */ | ||
81 | |||
82 | if (offset >= MAX3107_GPIO_COUNT) { | ||
83 | dev_err(&s->spi->dev, "Invalid GPIO\n"); | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | |||
87 | /* Read current GPIO configuration and data registers */ | ||
88 | buf[0] = MAX3107_GPIOCFG_REG; | ||
89 | buf[1] = MAX3107_GPIODATA_REG; | ||
90 | /* Perform SPI transfer */ | ||
91 | if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { | ||
92 | dev_err(&s->spi->dev, "SPI transfer gpio failed\n"); | ||
93 | return -EIO; | ||
94 | } | ||
95 | buf[0] &= MAX3107_SPI_RX_DATA_MASK; | ||
96 | buf[1] &= MAX3107_SPI_RX_DATA_MASK; | ||
97 | |||
98 | /* Set GPIO to output */ | ||
99 | buf[0] |= (0x0001 << offset); | ||
100 | /* Set value */ | ||
101 | if (value) | ||
102 | buf[1] |= (0x0001 << offset); | ||
103 | else | ||
104 | buf[1] &= ~(0x0001 << offset); | ||
105 | |||
106 | /* Write new GPIO configuration and data register values */ | ||
107 | buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); | ||
108 | buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); | ||
109 | /* Perform SPI transfer */ | ||
110 | if (max3107_rw(s, (u8 *)buf, NULL, 4)) { | ||
111 | dev_err(&s->spi->dev, | ||
112 | "SPI transfer for GPIO conf data w failed\n"); | ||
113 | return -EIO; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /* GPIO value query function */ | ||
119 | static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
120 | { | ||
121 | struct max3107_port *s = container_of(chip, struct max3107_port, chip); | ||
122 | u16 buf[1]; /* Buffer for SPI transfer */ | ||
123 | |||
124 | if (offset >= MAX3107_GPIO_COUNT) { | ||
125 | dev_err(&s->spi->dev, "Invalid GPIO\n"); | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | |||
129 | /* Read current GPIO data register */ | ||
130 | buf[0] = MAX3107_GPIODATA_REG; | ||
131 | /* Perform SPI transfer */ | ||
132 | if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { | ||
133 | dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n"); | ||
134 | return -EIO; | ||
135 | } | ||
136 | buf[0] &= MAX3107_SPI_RX_DATA_MASK; | ||
137 | |||
138 | /* Return value */ | ||
139 | return buf[0] & (0x0001 << offset); | ||
140 | } | ||
141 | |||
142 | /* GPIO value set function */ | ||
143 | static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
144 | { | ||
145 | struct max3107_port *s = container_of(chip, struct max3107_port, chip); | ||
146 | u16 buf[2]; /* Buffer for SPI transfers */ | ||
147 | |||
148 | if (offset >= MAX3107_GPIO_COUNT) { | ||
149 | dev_err(&s->spi->dev, "Invalid GPIO\n"); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | /* Read current GPIO configuration registers*/ | ||
154 | buf[0] = MAX3107_GPIODATA_REG; | ||
155 | buf[1] = MAX3107_GPIOCFG_REG; | ||
156 | /* Perform SPI transfer */ | ||
157 | if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { | ||
158 | dev_err(&s->spi->dev, | ||
159 | "SPI transfer for GPIO data and config read failed\n"); | ||
160 | return; | ||
161 | } | ||
162 | buf[0] &= MAX3107_SPI_RX_DATA_MASK; | ||
163 | buf[1] &= MAX3107_SPI_RX_DATA_MASK; | ||
164 | |||
165 | if (!(buf[1] & (0x0001 << offset))) { | ||
166 | /* Configured as input, can't set value */ | ||
167 | dev_warn(&s->spi->dev, | ||
168 | "Trying to set value for input GPIO\n"); | ||
169 | return; | ||
170 | } | ||
171 | |||
172 | /* Set value */ | ||
173 | if (value) | ||
174 | buf[0] |= (0x0001 << offset); | ||
175 | else | ||
176 | buf[0] &= ~(0x0001 << offset); | ||
177 | |||
178 | /* Write new GPIO data register value */ | ||
179 | buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); | ||
180 | /* Perform SPI transfer */ | ||
181 | if (max3107_rw(s, (u8 *)buf, NULL, 2)) | ||
182 | dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n"); | ||
183 | } | ||
184 | |||
185 | /* GPIO chip data */ | ||
186 | static struct gpio_chip max3107_gpio_chip = { | ||
187 | .owner = THIS_MODULE, | ||
188 | .direction_input = max3107_gpio_direction_in, | ||
189 | .direction_output = max3107_gpio_direction_out, | ||
190 | .get = max3107_gpio_get, | ||
191 | .set = max3107_gpio_set, | ||
192 | .can_sleep = 1, | ||
193 | .base = MAX3107_GPIO_BASE, | ||
194 | .ngpio = MAX3107_GPIO_COUNT, | ||
195 | }; | ||
196 | |||
197 | /** | ||
198 | * max3107_aava_reset - reset on AAVA systems | ||
199 | * @spi: The SPI device we are probing | ||
200 | * | ||
201 | * Reset the device ready for probing. | ||
202 | */ | ||
203 | |||
204 | static int max3107_aava_reset(struct spi_device *spi) | ||
205 | { | ||
206 | /* Reset the chip */ | ||
207 | if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { | ||
208 | pr_err("Requesting RESET GPIO failed\n"); | ||
209 | return -EIO; | ||
210 | } | ||
211 | if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { | ||
212 | pr_err("Setting RESET GPIO to 0 failed\n"); | ||
213 | gpio_free(MAX3107_RESET_GPIO); | ||
214 | return -EIO; | ||
215 | } | ||
216 | msleep(MAX3107_RESET_DELAY); | ||
217 | if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) { | ||
218 | pr_err("Setting RESET GPIO to 1 failed\n"); | ||
219 | gpio_free(MAX3107_RESET_GPIO); | ||
220 | return -EIO; | ||
221 | } | ||
222 | gpio_free(MAX3107_RESET_GPIO); | ||
223 | msleep(MAX3107_WAKEUP_DELAY); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int max3107_aava_configure(struct max3107_port *s) | ||
228 | { | ||
229 | int retval; | ||
230 | |||
231 | /* Initialize GPIO chip data */ | ||
232 | s->chip = max3107_gpio_chip; | ||
233 | s->chip.label = s->spi->modalias; | ||
234 | s->chip.dev = &s->spi->dev; | ||
235 | |||
236 | /* Add GPIO chip */ | ||
237 | retval = gpiochip_add(&s->chip); | ||
238 | if (retval) { | ||
239 | dev_err(&s->spi->dev, "Adding GPIO chip failed\n"); | ||
240 | return retval; | ||
241 | } | ||
242 | |||
243 | /* Temporary fix for EV2 boot problems, set modem reset to 0 */ | ||
244 | max3107_gpio_direction_out(&s->chip, 3, 0); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | #if 0 | ||
249 | /* This will get enabled once we have the board stuff merged for this | ||
250 | specific case */ | ||
251 | |||
252 | static const struct baud_table brg13_ext[] = { | ||
253 | { 300, MAX3107_BRG13_B300 }, | ||
254 | { 600, MAX3107_BRG13_B600 }, | ||
255 | { 1200, MAX3107_BRG13_B1200 }, | ||
256 | { 2400, MAX3107_BRG13_B2400 }, | ||
257 | { 4800, MAX3107_BRG13_B4800 }, | ||
258 | { 9600, MAX3107_BRG13_B9600 }, | ||
259 | { 19200, MAX3107_BRG13_B19200 }, | ||
260 | { 57600, MAX3107_BRG13_B57600 }, | ||
261 | { 115200, MAX3107_BRG13_B115200 }, | ||
262 | { 230400, MAX3107_BRG13_B230400 }, | ||
263 | { 460800, MAX3107_BRG13_B460800 }, | ||
264 | { 921600, MAX3107_BRG13_B921600 }, | ||
265 | { 0, 0 } | ||
266 | }; | ||
267 | |||
268 | static void max3107_aava_init(struct max3107_port *s) | ||
269 | { | ||
270 | /*override for AAVA SC specific*/ | ||
271 | if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { | ||
272 | if (get_koski_build_id() <= KOSKI_EV2) | ||
273 | if (s->ext_clk) { | ||
274 | s->brg_cfg = MAX3107_BRG13_B9600; | ||
275 | s->baud_tbl = (struct baud_table *)brg13_ext; | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | #endif | ||
280 | |||
281 | static int __devexit max3107_aava_remove(struct spi_device *spi) | ||
282 | { | ||
283 | struct max3107_port *s = dev_get_drvdata(&spi->dev); | ||
284 | |||
285 | /* Remove GPIO chip */ | ||
286 | if (gpiochip_remove(&s->chip)) | ||
287 | dev_warn(&spi->dev, "Removing GPIO chip failed\n"); | ||
288 | |||
289 | /* Then do the default remove */ | ||
290 | return max3107_remove(spi); | ||
291 | } | ||
292 | |||
293 | /* Platform data */ | ||
294 | static struct max3107_plat aava_plat_data = { | ||
295 | .loopback = 0, | ||
296 | .ext_clk = 1, | ||
297 | /* .init = max3107_aava_init, */ | ||
298 | .configure = max3107_aava_configure, | ||
299 | .hw_suspend = max3107_hw_susp, | ||
300 | .polled_mode = 0, | ||
301 | .poll_time = 0, | ||
302 | }; | ||
303 | |||
304 | |||
305 | static int __devinit max3107_probe_aava(struct spi_device *spi) | ||
306 | { | ||
307 | int err = max3107_aava_reset(spi); | ||
308 | if (err < 0) | ||
309 | return err; | ||
310 | return max3107_probe(spi, &aava_plat_data); | ||
311 | } | ||
312 | |||
313 | /* Spi driver data */ | ||
314 | static struct spi_driver max3107_driver = { | ||
315 | .driver = { | ||
316 | .name = "aava-max3107", | ||
317 | .bus = &spi_bus_type, | ||
318 | .owner = THIS_MODULE, | ||
319 | }, | ||
320 | .probe = max3107_probe_aava, | ||
321 | .remove = __devexit_p(max3107_aava_remove), | ||
322 | .suspend = max3107_suspend, | ||
323 | .resume = max3107_resume, | ||
324 | }; | ||
325 | |||
326 | /* Driver init function */ | ||
327 | static int __init max3107_init(void) | ||
328 | { | ||
329 | return spi_register_driver(&max3107_driver); | ||
330 | } | ||
331 | |||
332 | /* Driver exit function */ | ||
333 | static void __exit max3107_exit(void) | ||
334 | { | ||
335 | spi_unregister_driver(&max3107_driver); | ||
336 | } | ||
337 | |||
338 | module_init(max3107_init); | ||
339 | module_exit(max3107_exit); | ||
340 | |||
341 | MODULE_DESCRIPTION("MAX3107 driver"); | ||
342 | MODULE_AUTHOR("Aavamobile"); | ||
343 | MODULE_ALIAS("aava-max3107-spi"); | ||
344 | MODULE_LICENSE("GPL v2"); | ||