Root/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
38struct rb4xx_cpld {
39    struct spi_device *spi;
40    struct mutex lock;
41    struct gpio_chip chip;
42    unsigned int config;
43};
44
45static struct rb4xx_cpld *rb4xx_cpld;
46
47static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
48{
49    return container_of(chip, struct rb4xx_cpld, chip);
50}
51
52static 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
72static 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
93static 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
119int 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}
132EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
133
134int 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}
167EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
168
169#if 0
170int 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
199int 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
225EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
226
227int 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}
284EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
285
286static 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
298static 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
308static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
309                       unsigned offset)
310{
311    return -EOPNOTSUPP;
312}
313
314static 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
328static 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
359static int __devinit 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
397err_drvdata:
398    dev_set_drvdata(&spi->dev, NULL);
399    kfree(cpld);
400
401    return err;
402}
403
404static int __devexit 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
416static 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 = __devexit_p(rb4xx_cpld_remove),
424};
425
426static int __init rb4xx_cpld_init(void)
427{
428    return spi_register_driver(&rb4xx_cpld_driver);
429}
430module_init(rb4xx_cpld_init);
431
432static void __exit rb4xx_cpld_exit(void)
433{
434    spi_unregister_driver(&rb4xx_cpld_driver);
435}
436module_exit(rb4xx_cpld_exit);
437
438MODULE_DESCRIPTION(DRV_DESC);
439MODULE_VERSION(DRV_VERSION);
440MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
441MODULE_LICENSE("GPL v2");
442

Archive Download this file



interactive