OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [spi/] [tle62x0.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * tle62x0.c -- support Infineon TLE62x0 driver chips
3
 *
4
 * Copyright (c) 2007 Simtec Electronics
5
 *      Ben Dooks, <ben@simtec.co.uk>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License version 2 as
9
 * published by the Free Software Foundation.
10
 */
11
 
12
#include <linux/device.h>
13
#include <linux/kernel.h>
14
 
15
#include <linux/spi/spi.h>
16
#include <linux/spi/tle62x0.h>
17
 
18
 
19
#define CMD_READ        0x00
20
#define CMD_SET         0xff
21
 
22
#define DIAG_NORMAL     0x03
23
#define DIAG_OVERLOAD   0x02
24
#define DIAG_OPEN       0x01
25
#define DIAG_SHORTGND   0x00
26
 
27
struct tle62x0_state {
28
        struct spi_device       *us;
29
        struct mutex            lock;
30
        unsigned int            nr_gpio;
31
        unsigned int            gpio_state;
32
 
33
        unsigned char           tx_buff[4];
34
        unsigned char           rx_buff[4];
35
};
36
 
37
static int to_gpio_num(struct device_attribute *attr);
38
 
39
static inline int tle62x0_write(struct tle62x0_state *st)
40
{
41
        unsigned char *buff = st->tx_buff;
42
        unsigned int gpio_state = st->gpio_state;
43
 
44
        buff[0] = CMD_SET;
45
 
46
        if (st->nr_gpio == 16) {
47
                buff[1] = gpio_state >> 8;
48
                buff[2] = gpio_state;
49
        } else {
50
                buff[1] = gpio_state;
51
        }
52
 
53
        dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
54
                buff[0], buff[1], buff[2]);
55
 
56
        return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
57
}
58
 
59
static inline int tle62x0_read(struct tle62x0_state *st)
60
{
61
        unsigned char *txbuff = st->tx_buff;
62
        struct spi_transfer xfer = {
63
                .tx_buf         = txbuff,
64
                .rx_buf         = st->rx_buff,
65
                .len            = (st->nr_gpio * 2) / 8,
66
        };
67
        struct spi_message msg;
68
 
69
        txbuff[0] = CMD_READ;
70
        txbuff[1] = 0x00;
71
        txbuff[2] = 0x00;
72
        txbuff[3] = 0x00;
73
 
74
        spi_message_init(&msg);
75
        spi_message_add_tail(&xfer, &msg);
76
 
77
        return spi_sync(st->us, &msg);
78
}
79
 
80
static unsigned char *decode_fault(unsigned int fault_code)
81
{
82
        fault_code &= 3;
83
 
84
        switch (fault_code) {
85
        case DIAG_NORMAL:
86
                return "N";
87
        case DIAG_OVERLOAD:
88
                return "V";
89
        case DIAG_OPEN:
90
                return "O";
91
        case DIAG_SHORTGND:
92
                return "G";
93
        }
94
 
95
        return "?";
96
}
97
 
98
static ssize_t tle62x0_status_show(struct device *dev,
99
                struct device_attribute *attr, char *buf)
100
{
101
        struct tle62x0_state *st = dev_get_drvdata(dev);
102
        char *bp = buf;
103
        unsigned char *buff = st->rx_buff;
104
        unsigned long fault = 0;
105
        int ptr;
106
        int ret;
107
 
108
        mutex_lock(&st->lock);
109
        ret = tle62x0_read(st);
110
        dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
111
        if (ret < 0) {
112
                mutex_unlock(&st->lock);
113
                return ret;
114
        }
115
 
116
        for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
117
                fault <<= 8;
118
                fault  |= ((unsigned long)buff[ptr]);
119
 
120
                dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]);
121
        }
122
 
123
        for (ptr = 0; ptr < st->nr_gpio; ptr++) {
124
                bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2)));
125
        }
126
 
127
        *bp++ = '\n';
128
 
129
        mutex_unlock(&st->lock);
130
        return bp - buf;
131
}
132
 
133
static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL);
134
 
135
static ssize_t tle62x0_gpio_show(struct device *dev,
136
                struct device_attribute *attr, char *buf)
137
{
138
        struct tle62x0_state *st = dev_get_drvdata(dev);
139
        int gpio_num = to_gpio_num(attr);
140
        int value;
141
 
142
        mutex_lock(&st->lock);
143
        value = (st->gpio_state >> gpio_num) & 1;
144
        mutex_unlock(&st->lock);
145
 
146
        return snprintf(buf, PAGE_SIZE, "%d", value);
147
}
148
 
149
static ssize_t tle62x0_gpio_store(struct device *dev,
150
                struct device_attribute *attr,
151
                const char *buf, size_t len)
152
{
153
        struct tle62x0_state *st = dev_get_drvdata(dev);
154
        int gpio_num = to_gpio_num(attr);
155
        unsigned long val;
156
        char *endp;
157
 
158
        val = simple_strtoul(buf, &endp, 0);
159
        if (buf == endp)
160
                return -EINVAL;
161
 
162
        dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val);
163
 
164
        mutex_lock(&st->lock);
165
 
166
        if (val)
167
                st->gpio_state |= 1 << gpio_num;
168
        else
169
                st->gpio_state &= ~(1 << gpio_num);
170
 
171
        tle62x0_write(st);
172
        mutex_unlock(&st->lock);
173
 
174
        return len;
175
}
176
 
177
static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO,
178
                tle62x0_gpio_show, tle62x0_gpio_store);
179
static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO,
180
                tle62x0_gpio_show, tle62x0_gpio_store);
181
static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO,
182
                tle62x0_gpio_show, tle62x0_gpio_store);
183
static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO,
184
                tle62x0_gpio_show, tle62x0_gpio_store);
185
static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO,
186
                tle62x0_gpio_show, tle62x0_gpio_store);
187
static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO,
188
                tle62x0_gpio_show, tle62x0_gpio_store);
189
static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO,
190
                tle62x0_gpio_show, tle62x0_gpio_store);
191
static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO,
192
                tle62x0_gpio_show, tle62x0_gpio_store);
193
static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO,
194
                tle62x0_gpio_show, tle62x0_gpio_store);
195
static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO,
196
                tle62x0_gpio_show, tle62x0_gpio_store);
197
static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO,
198
                tle62x0_gpio_show, tle62x0_gpio_store);
199
static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO,
200
                tle62x0_gpio_show, tle62x0_gpio_store);
201
static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO,
202
                tle62x0_gpio_show, tle62x0_gpio_store);
203
static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO,
204
                tle62x0_gpio_show, tle62x0_gpio_store);
205
static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO,
206
                tle62x0_gpio_show, tle62x0_gpio_store);
207
static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO,
208
                tle62x0_gpio_show, tle62x0_gpio_store);
209
 
210
static struct device_attribute *gpio_attrs[] = {
211
        [0]              = &dev_attr_gpio1,
212
        [1]             = &dev_attr_gpio2,
213
        [2]             = &dev_attr_gpio3,
214
        [3]             = &dev_attr_gpio4,
215
        [4]             = &dev_attr_gpio5,
216
        [5]             = &dev_attr_gpio6,
217
        [6]             = &dev_attr_gpio7,
218
        [7]             = &dev_attr_gpio8,
219
        [8]             = &dev_attr_gpio9,
220
        [9]             = &dev_attr_gpio10,
221
        [10]            = &dev_attr_gpio11,
222
        [11]            = &dev_attr_gpio12,
223
        [12]            = &dev_attr_gpio13,
224
        [13]            = &dev_attr_gpio14,
225
        [14]            = &dev_attr_gpio15,
226
        [15]            = &dev_attr_gpio16
227
};
228
 
229
static int to_gpio_num(struct device_attribute *attr)
230
{
231
        int ptr;
232
 
233
        for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) {
234
                if (gpio_attrs[ptr] == attr)
235
                        return ptr;
236
        }
237
 
238
        return -1;
239
}
240
 
241
static int __devinit tle62x0_probe(struct spi_device *spi)
242
{
243
        struct tle62x0_state *st;
244
        struct tle62x0_pdata *pdata;
245
        int ptr;
246
        int ret;
247
 
248
        pdata = spi->dev.platform_data;
249
        if (pdata == NULL) {
250
                dev_err(&spi->dev, "no device data specified\n");
251
                return -EINVAL;
252
        }
253
 
254
        st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL);
255
        if (st == NULL) {
256
                dev_err(&spi->dev, "no memory for device state\n");
257
                return -ENOMEM;
258
        }
259
 
260
        st->us = spi;
261
        st->nr_gpio = pdata->gpio_count;
262
        st->gpio_state = pdata->init_state;
263
 
264
        mutex_init(&st->lock);
265
 
266
        ret = device_create_file(&spi->dev, &dev_attr_status_show);
267
        if (ret) {
268
                dev_err(&spi->dev, "cannot create status attribute\n");
269
                goto err_status;
270
        }
271
 
272
        for (ptr = 0; ptr < pdata->gpio_count; ptr++) {
273
                ret = device_create_file(&spi->dev, gpio_attrs[ptr]);
274
                if (ret) {
275
                        dev_err(&spi->dev, "cannot create gpio attribute\n");
276
                        goto err_gpios;
277
                }
278
        }
279
 
280
        /* tle62x0_write(st); */
281
        spi_set_drvdata(spi, st);
282
        return 0;
283
 
284
 err_gpios:
285
        for (; ptr > 0; ptr--)
286
                device_remove_file(&spi->dev, gpio_attrs[ptr]);
287
 
288
        device_remove_file(&spi->dev, &dev_attr_status_show);
289
 
290
 err_status:
291
        kfree(st);
292
        return ret;
293
}
294
 
295
static int __devexit tle62x0_remove(struct spi_device *spi)
296
{
297
        struct tle62x0_state *st = spi_get_drvdata(spi);
298
        int ptr;
299
 
300
        for (ptr = 0; ptr < st->nr_gpio; ptr++)
301
                device_remove_file(&spi->dev, gpio_attrs[ptr]);
302
 
303
        kfree(st);
304
        return 0;
305
}
306
 
307
static struct spi_driver tle62x0_driver = {
308
        .driver = {
309
                .name   = "tle62x0",
310
                .owner  = THIS_MODULE,
311
        },
312
        .probe          = tle62x0_probe,
313
        .remove         = __devexit_p(tle62x0_remove),
314
};
315
 
316
static __init int tle62x0_init(void)
317
{
318
        return spi_register_driver(&tle62x0_driver);
319
}
320
 
321
static __exit void tle62x0_exit(void)
322
{
323
        spi_unregister_driver(&tle62x0_driver);
324
}
325
 
326
module_init(tle62x0_init);
327
module_exit(tle62x0_exit);
328
 
329
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
330
MODULE_DESCRIPTION("TLE62x0 SPI driver");
331
MODULE_LICENSE("GPL v2");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.