ar71xx: ag71xx: fix max frame length setup of the built-in switches
[openwrt.git] / target / linux / ar71xx / files / drivers / spi / spi-rb4xx-cpld.c
1 /*
2  * SPI driver for the CPLD chip on the Mikrotik RB4xx boards
3  *
4  * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
5  *
6  * This file was based on the patches for Linux 2.6.27.39 published by
7  * MikroTik for their RouterBoard 4xx series devices.
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published
11  * by the Free Software Foundation.
12  */
13
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/device.h>
20 #include <linux/bitops.h>
21 #include <linux/spi/spi.h>
22 #include <linux/gpio.h>
23 #include <linux/slab.h>
24
25 #include <asm/mach-ath79/rb4xx_cpld.h>
26
27 #define DRV_NAME        "spi-rb4xx-cpld"
28 #define DRV_DESC        "RB4xx CPLD driver"
29 #define DRV_VERSION     "0.1.0"
30
31 #define CPLD_CMD_WRITE_NAND     0x08 /* send cmd, n x send data, send indle */
32 #define CPLD_CMD_WRITE_CFG      0x09 /* send cmd, n x send cfg */
33 #define CPLD_CMD_READ_NAND      0x0a /* send cmd, send idle, n x read data */
34 #define CPLD_CMD_READ_FAST      0x0b /* send cmd, 4 x idle, n x read data */
35 #define CPLD_CMD_LED5_ON        0x0c /* send cmd */
36 #define CPLD_CMD_LED5_OFF       0x0d /* send cmd */
37
38 struct rb4xx_cpld {
39         struct spi_device       *spi;
40         struct mutex            lock;
41         struct gpio_chip        chip;
42         unsigned int            config;
43 };
44
45 static struct rb4xx_cpld *rb4xx_cpld;
46
47 static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
48 {
49         return container_of(chip, struct rb4xx_cpld, chip);
50 }
51
52 static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd)
53 {
54         struct spi_transfer t[1];
55         struct spi_message m;
56         unsigned char tx_buf[1];
57         int err;
58
59         spi_message_init(&m);
60         memset(&t, 0, sizeof(t));
61
62         t[0].tx_buf = tx_buf;
63         t[0].len = sizeof(tx_buf);
64         spi_message_add_tail(&t[0], &m);
65
66         tx_buf[0] = cmd;
67
68         err = spi_sync(cpld->spi, &m);
69         return err;
70 }
71
72 static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config)
73 {
74         struct spi_transfer t[1];
75         struct spi_message m;
76         unsigned char cmd[2];
77         int err;
78
79         spi_message_init(&m);
80         memset(&t, 0, sizeof(t));
81
82         t[0].tx_buf = cmd;
83         t[0].len = sizeof(cmd);
84         spi_message_add_tail(&t[0], &m);
85
86         cmd[0] = CPLD_CMD_WRITE_CFG;
87         cmd[1] = config;
88
89         err = spi_sync(cpld->spi, &m);
90         return err;
91 }
92
93 static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask,
94                                    unsigned value)
95 {
96         unsigned int config;
97         int err;
98
99         config = cpld->config & ~mask;
100         config |= value;
101
102         if ((cpld->config ^ config) & 0xff) {
103                 err = rb4xx_cpld_write_cfg(cpld, config);
104                 if (err)
105                         return err;
106         }
107
108         if ((cpld->config ^ config) & CPLD_CFG_nLED5) {
109                 err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON :
110                                                            CPLD_CMD_LED5_OFF);
111                 if (err)
112                         return err;
113         }
114
115         cpld->config = config;
116         return 0;
117 }
118
119 int rb4xx_cpld_change_cfg(unsigned mask, unsigned value)
120 {
121         int ret;
122
123         if (rb4xx_cpld == NULL)
124                 return -ENODEV;
125
126         mutex_lock(&rb4xx_cpld->lock);
127         ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value);
128         mutex_unlock(&rb4xx_cpld->lock);
129
130         return ret;
131 }
132 EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
133
134 int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf,
135                          const unsigned char *verify_buf, unsigned count)
136 {
137         const unsigned char cmd[5] = {
138                 CPLD_CMD_READ_FAST,
139                 (addr >> 16) & 0xff,
140                 (addr >> 8) & 0xff,
141                  addr & 0xff,
142                  0
143         };
144         struct spi_transfer t[2] = {
145                 {
146                         .tx_buf = &cmd,
147                         .len = 5,
148                 },
149                 {
150                         .tx_buf = verify_buf,
151                         .rx_buf = rx_buf,
152                         .len = count,
153                         .verify = (verify_buf != NULL),
154                 },
155         };
156         struct spi_message m;
157
158         if (rb4xx_cpld == NULL)
159                 return -ENODEV;
160
161         spi_message_init(&m);
162         m.fast_read = 1;
163         spi_message_add_tail(&t[0], &m);
164         spi_message_add_tail(&t[1], &m);
165         return spi_sync(rb4xx_cpld->spi, &m);
166 }
167 EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
168
169 #if 0
170 int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf,
171                     unsigned count)
172 {
173         struct spi_transfer t[2];
174         struct spi_message m;
175         unsigned char cmd[2];
176
177         if (rb4xx_cpld == NULL)
178                 return -ENODEV;
179
180         spi_message_init(&m);
181         memset(&t, 0, sizeof(t));
182
183         /* send command */
184         t[0].tx_buf = cmd;
185         t[0].len = sizeof(cmd);
186         spi_message_add_tail(&t[0], &m);
187
188         cmd[0] = CPLD_CMD_READ_NAND;
189         cmd[1] = 0;
190
191         /* read data */
192         t[1].rx_buf = buf;
193         t[1].len = count;
194         spi_message_add_tail(&t[1], &m);
195
196         return spi_sync(rb4xx_cpld->spi, &m);
197 }
198 #else
199 int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf,
200                     unsigned count)
201 {
202         static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 };
203         struct spi_transfer t[2] = {
204                 {
205                         .tx_buf = &cmd,
206                         .len = 2,
207                 }, {
208                         .tx_buf = verify_buf,
209                         .rx_buf = rx_buf,
210                         .len = count,
211                         .verify = (verify_buf != NULL),
212                 },
213         };
214         struct spi_message m;
215
216         if (rb4xx_cpld == NULL)
217                 return -ENODEV;
218
219         spi_message_init(&m);
220         spi_message_add_tail(&t[0], &m);
221         spi_message_add_tail(&t[1], &m);
222         return spi_sync(rb4xx_cpld->spi, &m);
223 }
224 #endif
225 EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
226
227 int rb4xx_cpld_write(const unsigned char *buf, unsigned count)
228 {
229 #if 0
230         struct spi_transfer t[3];
231         struct spi_message m;
232         unsigned char cmd[1];
233
234         if (rb4xx_cpld == NULL)
235                 return -ENODEV;
236
237         memset(&t, 0, sizeof(t));
238         spi_message_init(&m);
239
240         /* send command */
241         t[0].tx_buf = cmd;
242         t[0].len = sizeof(cmd);
243         spi_message_add_tail(&t[0], &m);
244
245         cmd[0] = CPLD_CMD_WRITE_NAND;
246
247         /* write data */
248         t[1].tx_buf = buf;
249         t[1].len = count;
250         spi_message_add_tail(&t[1], &m);
251
252         /* send idle */
253         t[2].len = 1;
254         spi_message_add_tail(&t[2], &m);
255
256         return spi_sync(rb4xx_cpld->spi, &m);
257 #else
258         static const unsigned char cmd = CPLD_CMD_WRITE_NAND;
259         struct spi_transfer t[3] = {
260                 {
261                         .tx_buf = &cmd,
262                         .len = 1,
263                 }, {
264                         .tx_buf = buf,
265                         .len = count,
266                         .fast_write = 1,
267                 }, {
268                         .len = 1,
269                         .fast_write = 1,
270                 },
271         };
272         struct spi_message m;
273
274         if (rb4xx_cpld == NULL)
275                 return -ENODEV;
276
277         spi_message_init(&m);
278         spi_message_add_tail(&t[0], &m);
279         spi_message_add_tail(&t[1], &m);
280         spi_message_add_tail(&t[2], &m);
281         return spi_sync(rb4xx_cpld->spi, &m);
282 #endif
283 }
284 EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
285
286 static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset)
287 {
288         struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
289         int ret;
290
291         mutex_lock(&cpld->lock);
292         ret = (cpld->config >> offset) & 1;
293         mutex_unlock(&cpld->lock);
294
295         return ret;
296 }
297
298 static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset,
299                                 int value)
300 {
301         struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
302
303         mutex_lock(&cpld->lock);
304         __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
305         mutex_unlock(&cpld->lock);
306 }
307
308 static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
309                                            unsigned offset)
310 {
311         return -EOPNOTSUPP;
312 }
313
314 static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip,
315                                             unsigned offset,
316                                             int value)
317 {
318         struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
319         int ret;
320
321         mutex_lock(&cpld->lock);
322         ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
323         mutex_unlock(&cpld->lock);
324
325         return ret;
326 }
327
328 static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base)
329 {
330         int err;
331
332         /* init config */
333         cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 |
334                        CPLD_CFG_nLED4 | CPLD_CFG_nCE;
335         rb4xx_cpld_write_cfg(cpld, cpld->config);
336
337         /* setup GPIO chip */
338         cpld->chip.label = DRV_NAME;
339
340         cpld->chip.get = rb4xx_cpld_gpio_get;
341         cpld->chip.set = rb4xx_cpld_gpio_set;
342         cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input;
343         cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output;
344
345         cpld->chip.base = base;
346         cpld->chip.ngpio = CPLD_NUM_GPIOS;
347         cpld->chip.can_sleep = 1;
348         cpld->chip.dev = &cpld->spi->dev;
349         cpld->chip.owner = THIS_MODULE;
350
351         err = gpiochip_add(&cpld->chip);
352         if (err)
353                 dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n",
354                         err);
355
356         return err;
357 }
358
359 static int rb4xx_cpld_probe(struct spi_device *spi)
360 {
361         struct rb4xx_cpld *cpld;
362         struct rb4xx_cpld_platform_data *pdata;
363         int err;
364
365         pdata = spi->dev.platform_data;
366         if (!pdata) {
367                 dev_dbg(&spi->dev, "no platform data\n");
368                 return -EINVAL;
369         }
370
371         cpld = kzalloc(sizeof(*cpld), GFP_KERNEL);
372         if (!cpld) {
373                 dev_err(&spi->dev, "no memory for private data\n");
374                 return -ENOMEM;
375         }
376
377         mutex_init(&cpld->lock);
378         cpld->spi = spi_dev_get(spi);
379         dev_set_drvdata(&spi->dev, cpld);
380
381         spi->mode = SPI_MODE_0;
382         spi->bits_per_word = 8;
383         err = spi_setup(spi);
384         if (err) {
385                 dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
386                 goto err_drvdata;
387         }
388
389         err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base);
390         if (err)
391                 goto err_drvdata;
392
393         rb4xx_cpld = cpld;
394
395         return 0;
396
397 err_drvdata:
398         dev_set_drvdata(&spi->dev, NULL);
399         kfree(cpld);
400
401         return err;
402 }
403
404 static int rb4xx_cpld_remove(struct spi_device *spi)
405 {
406         struct rb4xx_cpld *cpld;
407
408         rb4xx_cpld = NULL;
409         cpld = dev_get_drvdata(&spi->dev);
410         dev_set_drvdata(&spi->dev, NULL);
411         kfree(cpld);
412
413         return 0;
414 }
415
416 static struct spi_driver rb4xx_cpld_driver = {
417         .driver = {
418                 .name           = DRV_NAME,
419                 .bus            = &spi_bus_type,
420                 .owner          = THIS_MODULE,
421         },
422         .probe          = rb4xx_cpld_probe,
423         .remove         = rb4xx_cpld_remove,
424 };
425
426 static int __init rb4xx_cpld_init(void)
427 {
428         return spi_register_driver(&rb4xx_cpld_driver);
429 }
430 module_init(rb4xx_cpld_init);
431
432 static void __exit rb4xx_cpld_exit(void)
433 {
434         spi_unregister_driver(&rb4xx_cpld_driver);
435 }
436 module_exit(rb4xx_cpld_exit);
437
438 MODULE_DESCRIPTION(DRV_DESC);
439 MODULE_VERSION(DRV_VERSION);
440 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
441 MODULE_LICENSE("GPL v2");