2 * Support Infineon TLE62x0 driver chips
4 * Copyright (c) 2007 Simtec Electronics
5 * Ben Dooks, <ben@simtec.co.uk>
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.
12 #include <linux/device.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
17 #include <linux/spi/spi.h>
18 #include <linux/spi/tle62x0.h>
24 #define DIAG_NORMAL 0x03
25 #define DIAG_OVERLOAD 0x02
26 #define DIAG_OPEN 0x01
27 #define DIAG_SHORTGND 0x00
29 struct tle62x0_state
{
30 struct spi_device
*us
;
33 unsigned int gpio_state
;
35 unsigned char tx_buff
[4];
36 unsigned char rx_buff
[4];
39 static int to_gpio_num(struct device_attribute
*attr
);
41 static inline int tle62x0_write(struct tle62x0_state
*st
)
43 unsigned char *buff
= st
->tx_buff
;
44 unsigned int gpio_state
= st
->gpio_state
;
48 if (st
->nr_gpio
== 16) {
49 buff
[1] = gpio_state
>> 8;
55 dev_dbg(&st
->us
->dev
, "buff %02x,%02x,%02x\n",
56 buff
[0], buff
[1], buff
[2]);
58 return spi_write(st
->us
, buff
, (st
->nr_gpio
== 16) ? 3 : 2);
61 static inline int tle62x0_read(struct tle62x0_state
*st
)
63 unsigned char *txbuff
= st
->tx_buff
;
64 struct spi_transfer xfer
= {
66 .rx_buf
= st
->rx_buff
,
67 .len
= (st
->nr_gpio
* 2) / 8,
69 struct spi_message msg
;
76 spi_message_init(&msg
);
77 spi_message_add_tail(&xfer
, &msg
);
79 return spi_sync(st
->us
, &msg
);
82 static unsigned char *decode_fault(unsigned int fault_code
)
100 static ssize_t
tle62x0_status_show(struct device
*dev
,
101 struct device_attribute
*attr
, char *buf
)
103 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
105 unsigned char *buff
= st
->rx_buff
;
106 unsigned long fault
= 0;
110 mutex_lock(&st
->lock
);
111 ret
= tle62x0_read(st
);
112 dev_dbg(dev
, "tle62x0_read() returned %d\n", ret
);
114 mutex_unlock(&st
->lock
);
118 for (ptr
= 0; ptr
< (st
->nr_gpio
* 2)/8; ptr
+= 1) {
120 fault
|= ((unsigned long)buff
[ptr
]);
122 dev_dbg(dev
, "byte %d is %02x\n", ptr
, buff
[ptr
]);
125 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++) {
126 bp
+= sprintf(bp
, "%s ", decode_fault(fault
>> (ptr
* 2)));
131 mutex_unlock(&st
->lock
);
135 static DEVICE_ATTR(status_show
, S_IRUGO
, tle62x0_status_show
, NULL
);
137 static ssize_t
tle62x0_gpio_show(struct device
*dev
,
138 struct device_attribute
*attr
, char *buf
)
140 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
141 int gpio_num
= to_gpio_num(attr
);
144 mutex_lock(&st
->lock
);
145 value
= (st
->gpio_state
>> gpio_num
) & 1;
146 mutex_unlock(&st
->lock
);
148 return snprintf(buf
, PAGE_SIZE
, "%d", value
);
151 static ssize_t
tle62x0_gpio_store(struct device
*dev
,
152 struct device_attribute
*attr
,
153 const char *buf
, size_t len
)
155 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
156 int gpio_num
= to_gpio_num(attr
);
160 val
= simple_strtoul(buf
, &endp
, 0);
164 dev_dbg(dev
, "setting gpio %d to %ld\n", gpio_num
, val
);
166 mutex_lock(&st
->lock
);
169 st
->gpio_state
|= 1 << gpio_num
;
171 st
->gpio_state
&= ~(1 << gpio_num
);
174 mutex_unlock(&st
->lock
);
179 static DEVICE_ATTR(gpio1
, S_IWUSR
|S_IRUGO
,
180 tle62x0_gpio_show
, tle62x0_gpio_store
);
181 static DEVICE_ATTR(gpio2
, S_IWUSR
|S_IRUGO
,
182 tle62x0_gpio_show
, tle62x0_gpio_store
);
183 static DEVICE_ATTR(gpio3
, S_IWUSR
|S_IRUGO
,
184 tle62x0_gpio_show
, tle62x0_gpio_store
);
185 static DEVICE_ATTR(gpio4
, S_IWUSR
|S_IRUGO
,
186 tle62x0_gpio_show
, tle62x0_gpio_store
);
187 static DEVICE_ATTR(gpio5
, S_IWUSR
|S_IRUGO
,
188 tle62x0_gpio_show
, tle62x0_gpio_store
);
189 static DEVICE_ATTR(gpio6
, S_IWUSR
|S_IRUGO
,
190 tle62x0_gpio_show
, tle62x0_gpio_store
);
191 static DEVICE_ATTR(gpio7
, S_IWUSR
|S_IRUGO
,
192 tle62x0_gpio_show
, tle62x0_gpio_store
);
193 static DEVICE_ATTR(gpio8
, S_IWUSR
|S_IRUGO
,
194 tle62x0_gpio_show
, tle62x0_gpio_store
);
195 static DEVICE_ATTR(gpio9
, S_IWUSR
|S_IRUGO
,
196 tle62x0_gpio_show
, tle62x0_gpio_store
);
197 static DEVICE_ATTR(gpio10
, S_IWUSR
|S_IRUGO
,
198 tle62x0_gpio_show
, tle62x0_gpio_store
);
199 static DEVICE_ATTR(gpio11
, S_IWUSR
|S_IRUGO
,
200 tle62x0_gpio_show
, tle62x0_gpio_store
);
201 static DEVICE_ATTR(gpio12
, S_IWUSR
|S_IRUGO
,
202 tle62x0_gpio_show
, tle62x0_gpio_store
);
203 static DEVICE_ATTR(gpio13
, S_IWUSR
|S_IRUGO
,
204 tle62x0_gpio_show
, tle62x0_gpio_store
);
205 static DEVICE_ATTR(gpio14
, S_IWUSR
|S_IRUGO
,
206 tle62x0_gpio_show
, tle62x0_gpio_store
);
207 static DEVICE_ATTR(gpio15
, S_IWUSR
|S_IRUGO
,
208 tle62x0_gpio_show
, tle62x0_gpio_store
);
209 static DEVICE_ATTR(gpio16
, S_IWUSR
|S_IRUGO
,
210 tle62x0_gpio_show
, tle62x0_gpio_store
);
212 static struct device_attribute
*gpio_attrs
[] = {
213 [0] = &dev_attr_gpio1
,
214 [1] = &dev_attr_gpio2
,
215 [2] = &dev_attr_gpio3
,
216 [3] = &dev_attr_gpio4
,
217 [4] = &dev_attr_gpio5
,
218 [5] = &dev_attr_gpio6
,
219 [6] = &dev_attr_gpio7
,
220 [7] = &dev_attr_gpio8
,
221 [8] = &dev_attr_gpio9
,
222 [9] = &dev_attr_gpio10
,
223 [10] = &dev_attr_gpio11
,
224 [11] = &dev_attr_gpio12
,
225 [12] = &dev_attr_gpio13
,
226 [13] = &dev_attr_gpio14
,
227 [14] = &dev_attr_gpio15
,
228 [15] = &dev_attr_gpio16
231 static int to_gpio_num(struct device_attribute
*attr
)
235 for (ptr
= 0; ptr
< ARRAY_SIZE(gpio_attrs
); ptr
++) {
236 if (gpio_attrs
[ptr
] == attr
)
243 static int __devinit
tle62x0_probe(struct spi_device
*spi
)
245 struct tle62x0_state
*st
;
246 struct tle62x0_pdata
*pdata
;
250 pdata
= spi
->dev
.platform_data
;
252 dev_err(&spi
->dev
, "no device data specified\n");
256 st
= kzalloc(sizeof(struct tle62x0_state
), GFP_KERNEL
);
258 dev_err(&spi
->dev
, "no memory for device state\n");
263 st
->nr_gpio
= pdata
->gpio_count
;
264 st
->gpio_state
= pdata
->init_state
;
266 mutex_init(&st
->lock
);
268 ret
= device_create_file(&spi
->dev
, &dev_attr_status_show
);
270 dev_err(&spi
->dev
, "cannot create status attribute\n");
274 for (ptr
= 0; ptr
< pdata
->gpio_count
; ptr
++) {
275 ret
= device_create_file(&spi
->dev
, gpio_attrs
[ptr
]);
277 dev_err(&spi
->dev
, "cannot create gpio attribute\n");
282 /* tle62x0_write(st); */
283 spi_set_drvdata(spi
, st
);
288 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
290 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
297 static int __devexit
tle62x0_remove(struct spi_device
*spi
)
299 struct tle62x0_state
*st
= spi_get_drvdata(spi
);
302 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++)
303 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
305 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
310 static struct spi_driver tle62x0_driver
= {
313 .owner
= THIS_MODULE
,
315 .probe
= tle62x0_probe
,
316 .remove
= __devexit_p(tle62x0_remove
),
319 static __init
int tle62x0_init(void)
321 return spi_register_driver(&tle62x0_driver
);
324 static __exit
void tle62x0_exit(void)
326 spi_unregister_driver(&tle62x0_driver
);
329 module_init(tle62x0_init
);
330 module_exit(tle62x0_exit
);
332 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
333 MODULE_DESCRIPTION("TLE62x0 SPI driver");
334 MODULE_LICENSE("GPL v2");
335 MODULE_ALIAS("spi:tle62x0");