2 * tle62x0.c -- 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>
15 #include <linux/spi/spi.h>
16 #include <linux/spi/tle62x0.h>
22 #define DIAG_NORMAL 0x03
23 #define DIAG_OVERLOAD 0x02
24 #define DIAG_OPEN 0x01
25 #define DIAG_SHORTGND 0x00
27 struct tle62x0_state
{
28 struct spi_device
*us
;
31 unsigned int gpio_state
;
33 unsigned char tx_buff
[4];
34 unsigned char rx_buff
[4];
37 static int to_gpio_num(struct device_attribute
*attr
);
39 static inline int tle62x0_write(struct tle62x0_state
*st
)
41 unsigned char *buff
= st
->tx_buff
;
42 unsigned int gpio_state
= st
->gpio_state
;
46 if (st
->nr_gpio
== 16) {
47 buff
[1] = gpio_state
>> 8;
53 dev_dbg(&st
->us
->dev
, "buff %02x,%02x,%02x\n",
54 buff
[0], buff
[1], buff
[2]);
56 return spi_write(st
->us
, buff
, (st
->nr_gpio
== 16) ? 3 : 2);
59 static inline int tle62x0_read(struct tle62x0_state
*st
)
61 unsigned char *txbuff
= st
->tx_buff
;
62 struct spi_transfer xfer
= {
64 .rx_buf
= st
->rx_buff
,
65 .len
= (st
->nr_gpio
* 2) / 8,
67 struct spi_message msg
;
74 spi_message_init(&msg
);
75 spi_message_add_tail(&xfer
, &msg
);
77 return spi_sync(st
->us
, &msg
);
80 static unsigned char *decode_fault(unsigned int fault_code
)
98 static ssize_t
tle62x0_status_show(struct device
*dev
,
99 struct device_attribute
*attr
, char *buf
)
101 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
103 unsigned char *buff
= st
->rx_buff
;
104 unsigned long fault
= 0;
108 mutex_lock(&st
->lock
);
109 ret
= tle62x0_read(st
);
110 dev_dbg(dev
, "tle62x0_read() returned %d\n", ret
);
112 mutex_unlock(&st
->lock
);
116 for (ptr
= 0; ptr
< (st
->nr_gpio
* 2)/8; ptr
+= 1) {
118 fault
|= ((unsigned long)buff
[ptr
]);
120 dev_dbg(dev
, "byte %d is %02x\n", ptr
, buff
[ptr
]);
123 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++) {
124 bp
+= sprintf(bp
, "%s ", decode_fault(fault
>> (ptr
* 2)));
129 mutex_unlock(&st
->lock
);
133 static DEVICE_ATTR(status_show
, S_IRUGO
, tle62x0_status_show
, NULL
);
135 static ssize_t
tle62x0_gpio_show(struct device
*dev
,
136 struct device_attribute
*attr
, char *buf
)
138 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
139 int gpio_num
= to_gpio_num(attr
);
142 mutex_lock(&st
->lock
);
143 value
= (st
->gpio_state
>> gpio_num
) & 1;
144 mutex_unlock(&st
->lock
);
146 return snprintf(buf
, PAGE_SIZE
, "%d", value
);
149 static ssize_t
tle62x0_gpio_store(struct device
*dev
,
150 struct device_attribute
*attr
,
151 const char *buf
, size_t len
)
153 struct tle62x0_state
*st
= dev_get_drvdata(dev
);
154 int gpio_num
= to_gpio_num(attr
);
158 val
= simple_strtoul(buf
, &endp
, 0);
162 dev_dbg(dev
, "setting gpio %d to %ld\n", gpio_num
, val
);
164 mutex_lock(&st
->lock
);
167 st
->gpio_state
|= 1 << gpio_num
;
169 st
->gpio_state
&= ~(1 << gpio_num
);
172 mutex_unlock(&st
->lock
);
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
);
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
229 static int to_gpio_num(struct device_attribute
*attr
)
233 for (ptr
= 0; ptr
< ARRAY_SIZE(gpio_attrs
); ptr
++) {
234 if (gpio_attrs
[ptr
] == attr
)
241 static int __devinit
tle62x0_probe(struct spi_device
*spi
)
243 struct tle62x0_state
*st
;
244 struct tle62x0_pdata
*pdata
;
248 pdata
= spi
->dev
.platform_data
;
250 dev_err(&spi
->dev
, "no device data specified\n");
254 st
= kzalloc(sizeof(struct tle62x0_state
), GFP_KERNEL
);
256 dev_err(&spi
->dev
, "no memory for device state\n");
261 st
->nr_gpio
= pdata
->gpio_count
;
262 st
->gpio_state
= pdata
->init_state
;
264 mutex_init(&st
->lock
);
266 ret
= device_create_file(&spi
->dev
, &dev_attr_status_show
);
268 dev_err(&spi
->dev
, "cannot create status attribute\n");
272 for (ptr
= 0; ptr
< pdata
->gpio_count
; ptr
++) {
273 ret
= device_create_file(&spi
->dev
, gpio_attrs
[ptr
]);
275 dev_err(&spi
->dev
, "cannot create gpio attribute\n");
280 /* tle62x0_write(st); */
281 spi_set_drvdata(spi
, st
);
285 for (; ptr
> 0; ptr
--)
286 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
288 device_remove_file(&spi
->dev
, &dev_attr_status_show
);
295 static int __devexit
tle62x0_remove(struct spi_device
*spi
)
297 struct tle62x0_state
*st
= spi_get_drvdata(spi
);
300 for (ptr
= 0; ptr
< st
->nr_gpio
; ptr
++)
301 device_remove_file(&spi
->dev
, gpio_attrs
[ptr
]);
307 static struct spi_driver tle62x0_driver
= {
310 .owner
= THIS_MODULE
,
312 .probe
= tle62x0_probe
,
313 .remove
= __devexit_p(tle62x0_remove
),
316 static __init
int tle62x0_init(void)
318 return spi_register_driver(&tle62x0_driver
);
321 static __exit
void tle62x0_exit(void)
323 spi_unregister_driver(&tle62x0_driver
);
326 module_init(tle62x0_init
);
327 module_exit(tle62x0_exit
);
329 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
330 MODULE_DESCRIPTION("TLE62x0 SPI driver");
331 MODULE_LICENSE("GPL v2");